Session SATSolverVerification

Theory MoreList

(*    Title:              SATSolverVerification/MoreList.thy
      Author:             Filip Maric
      Maintainer:         Filip Maric <filip at matf.bg.ac.yu>
*)

section‹MoreList›

theory MoreList
imports Main "HOL-Library.Multiset"
begin

text‹Theory contains some additional lemmas and functions for the
@{term List} datatype. Warning: some of these notions are obsolete
because they already exist in {\em List.thy} in similiar form.›

(*********************************************************)
(*               last and butlast                        *)
(*********************************************************)
subsection@{term "last"} and @{term "butlast"} - last element of list and elements before it›
lemma listEqualsButlastAppendLast: 
  assumes "list  []"
  shows "list = (butlast list) @ [last list]"
using assms
by (induct list) auto

lemma lastListInList [simp]: 
  assumes "list  []"
  shows "last list  set list"
using assms
by (induct list) auto

lemma butlastIsSubset: 
  shows "set (butlast list)  set list"
by (induct list) (auto split: if_split_asm)

lemma setListIsSetButlastAndLast: 
  shows "set list  set (butlast list)  {last list}" 
by (induct list) auto

lemma butlastAppend: 
  shows "butlast (list1 @ list2) = (if list2 = [] then butlast list1 else (list1 @ butlast list2))"
by (induct list1) auto

(*********************************************************)
(*                   removeAll                           *)
(*********************************************************)
subsection@{term removeAll} - element removal›

lemma removeAll_multiset:
  assumes "distinct a" "x  set a"
  shows "mset a = {#x#} + mset (removeAll x a)"
using assms
proof (induct a)
  case (Cons y a')
  thus ?case
  proof (cases "x = y")
    case True
    with ‹distinct (y # a') x  set (y # a')
    have "¬  x  set a'"
      by auto
    hence "removeAll x a' = a'"
      by (rule removeAll_id)
    with x = y show ?thesis
      by (simp add: union_commute)
  next
    case False
    with x  set (y # a') 
    have "x  set a'"
      by simp
    with ‹distinct (y # a')
    have "x  y" "distinct a'"
      by auto
    hence "mset a' = {#x#} + mset (removeAll x a')"
      using x  set a'
      using Cons(1)
      by simp
    thus ?thesis
      using x  y
      by (simp add: union_assoc)
  qed
qed simp

lemma removeAll_map:
  assumes " x y. x  y  f x  f y"
  shows "removeAll (f x) (map f a) = map f (removeAll x a)"
using assms
by (induct a arbitrary: x) auto

 
(*********************************************************)
(*                   uniq                                *)
(*********************************************************)
subsection@{term uniq} - no duplicate elements.›
text@{term "(uniq list)"} holds iff there are no repeated elements
in a list.  Obsolete: same as @{term "distinct"} in {\em List.thy}.›

primrec uniq :: "'a list => bool"
where
"uniq [] = True" |
"uniq (h#t) = (h  set t  uniq t)"

lemma uniqDistinct:
"uniq l = distinct l"
by (induct l) auto

lemma uniqAppend: 
  assumes "uniq (l1 @ l2)" 
  shows "uniq l1" "uniq l2"
using assms
by (induct l1) auto

lemma uniqAppendIff: 
  "uniq (l1 @ l2) = (uniq l1  uniq l2  set l1  set l2 = {})" (is "?lhs = ?rhs")
by (induct l1) auto

lemma uniqAppendElement: 
  assumes "uniq l" 
  shows "e  set l = uniq (l @ [e])"
using assms
by (induct l) (auto split: if_split_asm)

lemma uniqImpliesNotLastMemButlast:
  assumes "uniq l"
  shows "last l  set (butlast l)"
proof (cases "l = []")
  case True
  thus ?thesis
    using assms
    by simp
next
  case False
  hence "l = butlast l @ [last l]"
    by (rule listEqualsButlastAppendLast)
  moreover
  with ‹uniq l 
  have "uniq (butlast l)"
    using uniqAppend[of "butlast l" "[last l]"]
    by simp
  ultimately
  show ?thesis
    using assms
    using uniqAppendElement[of "butlast l" "last l"]
    by simp
qed

lemma uniqButlastNotUniqListImpliesLastMemButlast: 
  assumes "uniq (butlast l)" "¬ uniq l" 
  shows "last l  set (butlast l)"
proof (cases "l = []")
  case True
  thus ?thesis
    using assms
    by auto
next
  case False
  hence "l = butlast l @ [(last l)]"
    by (rule listEqualsButlastAppendLast)
  thus ?thesis
    using assms
    using uniqAppendElement[of "butlast l" "last l"]
    by auto
qed

lemma uniqRemdups:
  shows "uniq (remdups x)"
by (induct x) auto

lemma uniqHeadTailSet:
  assumes "uniq l"
  shows "set (tl l) = (set l) - {hd l}"
using assms
by (induct l) auto

lemma uniqLengthEqCardSet:
assumes "uniq l"
shows "length l = card (set l)"
using assms
by (induct l) auto

lemma lengthGtOneTwoDistinctElements:
assumes 
  "uniq l" "length l > 1" "l  []"
shows
  " a1 a2. a1  set l  a2  set l  a1  a2"
proof-
  let ?a1 = "l ! 0"
  let ?a2 = "l ! 1"
  have "?a1  set l"
    using nth_mem[of "0" "l"]
    using assms
    by simp
  moreover
  have "?a2  set l"
    using nth_mem[of "1" "l"]
    using assms
    by simp
  moreover
  have "?a1  ?a2"
    using nth_eq_iff_index_eq[of "l" "0" "1"]
    using assms
    by (auto simp add: uniqDistinct)
  ultimately
  show ?thesis
    by auto
qed

(*********************************************************)
(*                   firstPos                            *)
(*********************************************************)
subsection @{term firstPos} - first position of an element›
text@{term "firstPos"} returns the zero-based index of the first
  occurrence of an element int a list, or the length of the list if the
  element does not occur.›

primrec firstPos :: "'a => 'a list => nat"
where
"firstPos a [] = 0" |
"firstPos a (h # t) = (if a = h then 0 else 1 + (firstPos a t))"

lemma firstPosEqualZero:
  shows "(firstPos a (m # M') = 0) = (a = m)"
by (induct M') auto

lemma firstPosLeLength: 
  assumes "a  set l"
  shows "firstPos a l < length l"
using assms
by (induct l) auto

lemma firstPosAppend: 
  assumes "a  set l" 
  shows "firstPos a l = firstPos a (l @ l')"
using assms
by (induct l) auto

lemma firstPosAppendNonMemberFirstMemberSecond: 
  assumes "a  set l1" and  "a  set l2"
  shows "firstPos a (l1 @ l2) = length l1 + firstPos a l2"
using assms
by (induct l1) auto

lemma firstPosDomainForElements: 
  shows "(0  firstPos a l  firstPos a l < length l) = (a  set l)" (is "?lhs = ?rhs")
  by (induct l) auto

lemma firstPosEqual: 
  assumes "a  set l" and "b  set l" 
  shows "(firstPos a l = firstPos b l) = (a = b)" (is "?lhs = ?rhs")
proof-
  {
    assume "?lhs"
    hence "?rhs"
      using assms
    proof (induct l)
      case (Cons m l')
      {
        assume "a = m"
        have "b = m"
        proof-
          from a = m 
          have "firstPos a (m # l') = 0"
            by simp
          with Cons 
          have "firstPos b (m # l') = 0"
            by simp
          with b  set (m # l') 
          have "firstPos b (m # l') = 0"
            by simp
          thus ?thesis
            using firstPosEqualZero[of "b" "m" "l'"]
            by simp
        qed
        with a = m 
        have ?case
          by simp
      }
      note * = this
      moreover
      {
        assume "b = m"
        have "a = m"
        proof-
          from b = m 
          have "firstPos b (m # l') = 0"
            by simp
          with Cons 
          have "firstPos a (m # l') = 0"
            by simp
          with a  set (m # l') 
          have "firstPos a (m # l') = 0"
            by simp
          thus ?thesis
            using firstPosEqualZero[of "a" "m" "l'"]
            by simp
        qed
        with b = m 
        have ?case
          by simp
      }
      note ** = this
      moreover
      {
        assume Q: "a  m" "b  m"
        from Q a  set (m # l')
        have "a  set l'"
          by simp
        from Q b  set (m # l')
        have "b  set l'"
          by simp
        from a  set l' b  set l' Cons
        have "firstPos a l' = firstPos b l'"
          by (simp split: if_split_asm)
        with Cons 
        have ?case
          by (simp split: if_split_asm)
      }
      note *** = this
      moreover
      {
        have "a = m  b = m  a  m  b  m"
          by auto
      }
      ultimately
      show ?thesis
      proof (cases "a = m")
        case True
        thus ?thesis
          by (rule *)
      next
        case False
        thus ?thesis
        proof (cases "b = m")
          case True
          thus ?thesis
            by (rule **)
        next
          case False
          with a  m show ?thesis
            by (rule ***)
        qed
      qed
    qed simp
  } thus ?thesis
    by auto
qed

lemma firstPosLast:
  assumes "l  []" "uniq l"
  shows "(firstPos x l = length l - 1) = (x = last l)"
using assms
by (induct l) auto


(*********************************************************)
(*                   precedes                            *)
(*********************************************************)
subsection@{term precedes} - ordering relation induced by @{term firstPos}
definition precedes :: "'a => 'a => 'a list => bool"
where
"precedes a b l == (a  set l  b  set l   firstPos a l <= firstPos b l)"

lemma noElementsPrecedesFirstElement: 
  assumes "a  b"
  shows "¬ precedes a b (b # list)"
proof-
  {
    assume "precedes a b (b # list)"
    hence "a  set (b # list)" "firstPos a (b # list) <= 0"
      unfolding precedes_def
      by (auto split: if_split_asm)
    hence  "firstPos a (b # list) = 0"
      by auto
    with a  b 
    have False
      using firstPosEqualZero[of "a" "b" "list"]
      by simp
  }
  thus ?thesis
    by auto
qed

lemma lastPrecedesNoElement:
assumes "uniq l"
shows "¬( a. a  last l  precedes (last l) a l)"
proof-
  {
    assume "¬ ?thesis"
    then obtain "a"
      where "precedes (last l) a l" "a  last l"
      by auto
    hence "a  set l" "last l  set l" "firstPos (last l) l  firstPos a l"
      unfolding precedes_def
      by auto
    hence "length l - 1  firstPos a l"
      using firstPosLast[of "l" "last l"]
      using ‹uniq l
      by force
    hence "firstPos a l = length l - 1"
      using firstPosDomainForElements[of "a" "l"]
      using a  set l
      by auto
    hence "a = last l"
      using firstPosLast[of "l" "last l"]
      using a  set l ‹last l  set l
      using ‹uniq l
      using firstPosEqual[of "a" "l" "last l"]
      by force
    with a  last l
    have False
      by simp
  }
  thus ?thesis
    by auto
qed

lemma precedesAppend: 
  assumes "precedes a b l" 
  shows "precedes a b (l @ l')"
proof-
  from ‹precedes a b l 
  have "a  set l" "b  set l" "firstPos a l  firstPos b l"
    unfolding precedes_def
    by (auto split: if_split_asm)
  thus ?thesis
    using firstPosAppend[of "a" "l" "l'"]
    using firstPosAppend[of "b" "l" "l'"]
    unfolding precedes_def
    by simp
qed

lemma precedesMemberHeadMemberTail: 
  assumes "a  set l1" and "b  set l1" and "b  set l2"
  shows "precedes a b (l1 @ l2)"
proof-
  from a  set l1 
  have "firstPos a l1 < length l1"
    using firstPosLeLength [of "a" "l1"]
    by simp
  moreover
  from a  set l1 
  have "firstPos a (l1 @ l2) = firstPos a l1"
    using firstPosAppend[of "a" "l1" "l2"]
    by simp
  moreover
  from b  set l1 b  set l2
  have "firstPos b (l1 @ l2) = length l1 + firstPos b l2"
    by (rule firstPosAppendNonMemberFirstMemberSecond)
  moreover
  have "firstPos b l2  0"
    by auto
  ultimately
  show ?thesis
    unfolding precedes_def
    using a  set l1 b  set l2
    by simp
qed


lemma precedesReflexivity: 
  assumes "a  set l"
  shows "precedes a a l"
using assms
unfolding precedes_def
by simp

lemma precedesTransitivity: 
  assumes 
  "precedes a b l" and "precedes b c l" 
  shows 
  "precedes a c l"
using assms
unfolding precedes_def
by auto

lemma precedesAntisymmetry: 
  assumes
  "a  set l" and "b  set l" and
  "precedes a b l" and "precedes b a l"
  shows
  "a = b"
proof-
  from assms
  have "firstPos a l = firstPos b l"
    unfolding precedes_def
    by auto
  thus ?thesis
    using firstPosEqual[of "a" "l" "b"]
    using assms
    by simp
qed

lemma precedesTotalOrder: 
  assumes "a  set l" and "b  set l"
  shows "a=b  precedes a b l  precedes b a l"
using assms
unfolding precedes_def
by auto

lemma precedesMap:
  assumes "precedes a b list" and " x y. x  y  f x  f y"
  shows "precedes (f a) (f b) (map f list)"
using assms
proof (induct list)
  case (Cons l list')
    {
      assume "a = l"
      have ?case
      proof-
        from a = l 
        have "firstPos (f a) (map f (l # list')) = 0"
          using firstPosEqualZero[of "f a" "f l" "map f list'"]
          by simp
        moreover
        from ‹precedes a b (l # list') 
        have "b  set (l # list')"
          unfolding precedes_def
          by simp
        hence "f b  set (map f (l # list'))"
          by auto
        moreover
        hence "firstPos (f b) (map f (l # list'))   0"
          by auto
        ultimately
        show ?thesis
          using a = l f b  set (map f (l # list'))
          unfolding precedes_def
          by simp
      qed
    }
    moreover
    {
      assume "b = l"
      with ‹precedes a b (l # list')
      have "a = l"
        using noElementsPrecedesFirstElement[of "a" "l" "list'"]
        by auto
      from a = l b = l 
      have ?case
        unfolding precedes_def
        by simp
    }
    moreover
    {
      assume "a  l" "b  l"
      with  x y. x  y  f x  f y
      have "f a  f l" "f b  f l"
        by auto
      from ‹precedes a b (l # list') 
      have "b  set(l # list')" "a  set(l # list')" "firstPos a (l # list')  firstPos b (l # list')"
        unfolding precedes_def
        by auto
      with a  l b  l 
      have "a  set list'" "b  set list'" "firstPos a list'  firstPos b list'"
        by auto
      hence "precedes a b list'"
        unfolding precedes_def
        by simp
      with Cons
      have "precedes (f a) (f b) (map f list')"
        by simp
      with f a  f l f b  f l
      have ?case
        unfolding precedes_def
        by auto
    }
    ultimately 
    show ?case
      by auto
next
  case Nil
  thus ?case
    unfolding precedes_def
    by simp
qed

lemma precedesFilter: 
  assumes "precedes a b list" and "f a" and "f b"
  shows "precedes a b (filter f list)"
using assms
proof(induct list)
  case (Cons l list')
  show ?case
  proof-
    from ‹precedes a b (l # list') 
    have "a  set(l # list')" "b  set(l # list')" "firstPos a (l # list')  firstPos b (l # list')"
      unfolding precedes_def
      by auto
    from f a a  set(l # list') 
    have "a  set(filter f (l # list'))"
      by auto
    moreover
    from f b b  set(l # list') 
    have "b  set(filter f (l # list'))"
      by auto
    moreover
    have "firstPos a (filter f (l # list'))  firstPos b (filter f (l # list'))"
    proof- 
      {
        assume "a = l"
        with f a 
        have "firstPos a (filter f (l # list')) = 0"
          by auto
        with b  set (filter f (l # list')) 
        have ?thesis
          by auto
      }
      moreover
      {
        assume "b = l"
        with ‹precedes a b (l # list')
        have "a = b"
          using noElementsPrecedesFirstElement[of "a" "b" "list'"]
          by auto
        hence ?thesis
          by (simp add: precedesReflexivity)
      }
      moreover
      {
        assume "a  l" "b  l"
        with ‹precedes a b (l # list') 
        have "firstPos a list'  firstPos b list'"
          unfolding precedes_def
          by auto
        moreover
        from a  l a  set (l # list') 
        have "a  set list'"
          by simp
        moreover
        from b  l b  set (l # list') 
        have "b  set list'"
          by simp
        ultimately
        have "precedes a b list'"
          unfolding precedes_def
          by simp
        with f a f b Cons(1)
        have "precedes a b (filter f list')"
          by simp
        with a  l b  l
        have ?thesis
          unfolding precedes_def
          by auto
      }
      ultimately
      show ?thesis
        by blast
    qed
    ultimately
    show ?thesis
      unfolding precedes_def
      by simp
  qed
qed simp

definition
"precedesOrder list == {(a, b). precedes a b list  a  b}"

lemma transPrecedesOrder: 
  "trans (precedesOrder list)"
proof-
  {
    fix x y z
    assume "precedes x y list" "x  y" "precedes y z list" "y  z"
    hence "precedes x z list" "x  z"
      using precedesTransitivity[of "x" "y" "list" "z"]
      using firstPosEqual[of "y" "list" "z"]
      unfolding precedes_def
      by auto
  }
  thus ?thesis
    unfolding trans_def
    unfolding precedesOrder_def
    by blast
qed
    

lemma wellFoundedPrecedesOrder:
  shows "wf (precedesOrder list)"
unfolding wf_eq_minimal
proof-
  show "Q a. a:Q  ( aMin  Q.  a'. (a', aMin)  precedesOrder list  a'  Q)"
  proof-
    {
      fix a :: "'a" and Q::"'a set"
      assume "a  Q"
      let ?listQ = "filter (λ x. x  Q) list"
      have " aMin  Q.  a'. (a', aMin)  precedesOrder list  a'  Q"
      proof (cases "?listQ = []")
        case True
        let ?aMin = a
        have " a'. (a', ?aMin)  precedesOrder list  a'  Q"
        proof-
          {
            fix a'
            assume "(a', ?aMin)  precedesOrder list"
            hence "a  set list"
              unfolding precedesOrder_def
              unfolding precedes_def
              by simp
            with a  Q
            have "a  set ?listQ"
              by (induct list) auto
            with ?listQ = [] 
            have "False"
              by simp
            hence "a'  Q"
              by simp
          }
          thus ?thesis
            by simp
        qed
        with a  Q obtain aMin where "aMin  Q" " a'. (a', aMin)  precedesOrder list  a'  Q"
          by auto
        thus ?thesis
          by auto
      next
        case False
        let ?aMin = "hd ?listQ"
        from False 
        have "?aMin  Q"
          by (induct list) auto
        have " a'. (a', ?aMin)  precedesOrder list  a'  Q"
        proof
          fix a'
          {
            assume "(a', ?aMin)  precedesOrder list"
            hence "a'  set list" "precedes a' ?aMin list" "a'  ?aMin"
              unfolding precedesOrder_def
              unfolding precedes_def
              by auto
            have "a'  Q"
            proof-
              {
                assume "a'  Q"
                with ?aMin  Q ‹precedes a' ?aMin list
                have "precedes a' ?aMin ?listQ"
                    using precedesFilter[of "a'" "?aMin" "list" "λ x. x  Q"]
                    by blast
                from a'  ?aMin 
                have "¬ precedes a' (hd ?listQ) (hd ?listQ # tl ?listQ)"
                  by (rule noElementsPrecedesFirstElement)
                with False ‹precedes a' ?aMin ?listQ
                have "False"
                  by auto
              }
              thus ?thesis
                by auto
            qed
          } thus "(a', ?aMin)  precedesOrder list  a'  Q"
            by simp
        qed
        with ?aMin  Q
        show ?thesis
          ..
      qed
    }
    thus ?thesis
      by simp
  qed
qed


(*********************************************************)
(*                   prefix                              *)
(*********************************************************)
subsection@{term isPrefix} - prefixes of list.›
text‹Check if a list is a prefix of another list. Obsolete: similiar
notion is defined in {\em List\_prefixes.thy}.›

definition
  isPrefix :: "'a list => 'a list => bool"
  where "isPrefix p t = ( s. p @ s = t)"

lemma prefixIsSubset:
  assumes "isPrefix p l"
  shows "set p  set l"
using assms
unfolding isPrefix_def
by auto

lemma uniqListImpliesUniqPrefix:
assumes "isPrefix p l" and "uniq l"
shows "uniq p"
proof-
  from ‹isPrefix p l obtain s
    where "p @ s = l"
    unfolding isPrefix_def
    by auto
  with ‹uniq l
  show ?thesis
    using uniqAppend[of "p" "s"]
    by simp
qed

lemma firstPosPrefixElement: 
  assumes "isPrefix p l" and "a  set p"
  shows "firstPos a p = firstPos a l"
proof-
  from ‹isPrefix p l obtain s
    where "p @ s = l"
    unfolding isPrefix_def
    by auto
  with a  set p 
  show ?thesis
    using firstPosAppend[of "a" "p" "s"]
    by simp
qed

lemma laterInPrefixRetainsPrecedes: 
  assumes 
  "isPrefix p l" and "precedes a b l" and "b  set p"
  shows 
  "precedes a b p"
proof-
  from ‹isPrefix p l obtain s
    where "p @ s = l"
    unfolding isPrefix_def
    by auto
  from ‹precedes a b l 
  have "a  set l" "b  set l" "firstPos a l  firstPos b l"
    unfolding precedes_def
    by (auto split: if_split_asm)

  from p @ s = l b  set p 
  have "firstPos b l = firstPos b p"
    using firstPosAppend [of "b" "p" "s"]
    by simp

  show ?thesis
  proof (cases "a  set p")
    case True
    from p @ s = l a  set p 
    have "firstPos a l = firstPos a p"
      using firstPosAppend [of "a" "p" "s"]
      by simp

    from ‹firstPos a l = firstPos a p ‹firstPos b l = firstPos b p ‹firstPos a l  firstPos b l
    a  set p b  set p
    show ?thesis
      unfolding precedes_def
      by simp
  next
    case False
    from a  set p a  set l p @ s = l
    have "a  set s"
      by auto
    with a  set p p @ s = l
    have "firstPos a l = length p + firstPos a s"
      using firstPosAppendNonMemberFirstMemberSecond[of "a" "p" "s"]
      by simp
    moreover
    from b  set p 
    have "firstPos b p < length p"
      by (rule firstPosLeLength)
    ultimately
    show ?thesis
      using ‹firstPos b l = firstPos b p ‹firstPos a l  firstPos b l
      by simp
  qed
qed

(*********************************************************)
(*                       List diff                       *)
(*********************************************************)
subsection@{term "list_diff"} - the set difference operation on two lists.›

primrec list_diff :: "'a list  'a list  'a list"
where
"list_diff x [] = x" |
"list_diff x (y#ys) = list_diff (removeAll y x) ys"

lemma [simp]: 
  shows "list_diff [] y = []"
by (induct y) auto

lemma [simp]: 
  shows "list_diff (x # xs) y = (if x  set y then list_diff xs y else x # list_diff xs y)"
proof (induct y arbitrary: xs)
  case (Cons y ys)
  thus ?case
  proof (cases "x = y")
    case True
    thus ?thesis
      by simp
  next
    case False
    thus ?thesis
    proof (cases "x  set ys")
      case True
      thus ?thesis
        using Cons
        by simp
    next
      case False
      thus ?thesis
        using Cons
        by simp
    qed
  qed
qed simp

lemma listDiffIff:
  shows "(x  set a  x  set b) = (x  set (list_diff a b))"
by (induct a) auto

lemma listDiffDoubleRemoveAll: 
  assumes "x  set a"
  shows "list_diff b a = list_diff b (x # a)"
using assms
by (induct b) auto

lemma removeAllListDiff[simp]:
  shows "removeAll x (list_diff a b) = list_diff (removeAll x a) b"
by (induct a) auto

lemma listDiffRemoveAllNonMember:
  assumes "x  set a"
  shows "list_diff a b = list_diff a (removeAll x b)"
using assms
proof (induct b arbitrary: a)
  case (Cons y b')
  from x  set a 
  have "x  set (removeAll y a)"
    by auto
  thus ?case
  proof (cases "x = y")
    case False
    thus ?thesis
      using Cons(2)
      using Cons(1)[of "removeAll y a"]
      using x  set (removeAll y a)
      by auto
  next
    case True
    thus ?thesis
      using Cons(1)[of "removeAll y a"]
      using x  set a
      using x  set (removeAll y a)
      by auto
  qed
qed simp

lemma listDiffMap: 
  assumes " x y. x  y  f x  f y"
  shows "map f (list_diff a b) = list_diff (map f a) (map f b)"
using assms
by (induct b arbitrary: a) (auto simp add: removeAll_map)

(*********************************************************)
(*                       Remdups                         *)
(*********************************************************)
subsection@{term remdups} - removing duplicates›
lemma remdupsRemoveAllCommute[simp]:
  shows "remdups (removeAll a list) = removeAll a (remdups list)"
by (induct list) auto

lemma remdupsAppend: 
  shows "remdups (a @ b) = remdups (list_diff a b) @ remdups b"
proof (induct a)
  case (Cons x a')
  thus ?case
    using listDiffIff[of "x" "a'" "b"]
    by auto
qed simp

lemma remdupsAppendSet: 
  shows "set (remdups (a @ b)) = set (remdups a @ remdups (list_diff b a))"
proof (induct a)
  case Nil
  thus ?case
    by auto
next
  case (Cons x a')
  thus ?case
  proof (cases "x  set a'")
    case True
    thus ?thesis
      using Cons
      using listDiffDoubleRemoveAll[of "x" "a'" "b"]
      by simp
  next
    case False
    thus ?thesis
    proof (cases "x  set b")
      case True
      show ?thesis
      proof-
        have "set (remdups (x # a') @ remdups (list_diff b (x # a'))) = 
          set (x # remdups a' @ remdups (list_diff b (x # a')))"
          using x  set a'
          by auto
        also have " = set (x # remdups a' @ remdups (list_diff (removeAll x b) a'))"
          by auto
        also have " = set (x # remdups a' @ remdups (removeAll x (list_diff b a')))"
          by simp
        also have " = set (remdups a' @ x # remdups (removeAll x (list_diff b a')))"
          by simp
        also have " = set (remdups a' @ x # removeAll x (remdups (list_diff b a')))"
          by (simp only: remdupsRemoveAllCommute)
        also have " = set (remdups a')  set (x # removeAll x (remdups (list_diff b a')))"
          by simp
        also have " = set (remdups a')  {x}  set (removeAll x (remdups (list_diff b a')))"
          by auto
        also have " = set (remdups a')  set (remdups (list_diff b a'))"
        proof-
          from x  set a' x  set b
          have "x  set (list_diff b a')"
            using listDiffIff[of "x" "b" "a'"]
            by simp
          hence "x  set (remdups (list_diff b a'))"
            by auto
          thus ?thesis
            by auto
        qed
        also have " = set (remdups (a' @ b))"
          using Cons(1)
          by simp
        also have " = set (remdups ((x # a') @ b))"
          using x  set b
          by simp
        finally show ?thesis
          by simp
      qed
    next
      case False
      thus ?thesis
      proof-
        have "set (remdups (x # a') @ remdups (list_diff b (x # a'))) = 
          set (x # (remdups a') @ remdups (list_diff b (x # a')))"
          using x  set a'
          by auto
        also have " = set (x # remdups a' @ remdups (list_diff (removeAll x b) a'))"
          by auto
        also have " = set (x # remdups a' @ remdups (list_diff b a'))"
          using x  set b
          by auto
        also have " = {x}  set (remdups (a' @ b))"
          using Cons(1)
          by simp
        also have " = set (remdups ((x # a') @ b))"
          by auto
        finally show ?thesis
          by simp
      qed
    qed
  qed
qed

lemma remdupsAppendMultiSet: 
  shows "mset (remdups (a @ b)) = mset (remdups a @ remdups (list_diff b a))"
proof (induct a)
  case Nil
  thus ?case
    by auto
next
  case (Cons x a')
  thus ?case
  proof (cases "x  set a'")
    case True
    thus ?thesis
      using Cons
      using listDiffDoubleRemoveAll[of "x" "a'" "b"]
      by simp
    next
    case False
    thus ?thesis
    proof (cases "x  set b")
      case True
      show ?thesis
      proof-
        have "mset (remdups (x # a') @ remdups (list_diff b (x # a'))) = 
          mset (x # remdups a' @ remdups (list_diff b (x # a')))"
        proof-
          have "remdups (x # a') = x # remdups a'"
            using x  set a'
            by auto
          thus ?thesis
            by simp
        qed
        also have " = mset (x # remdups a' @ remdups (list_diff (removeAll x b) a'))"
          by auto
        also have " = mset (x # remdups a' @ remdups (removeAll x (list_diff b a')))"
          by simp
        also have " = mset (remdups a' @ x # remdups (removeAll x (list_diff b a')))"
          by (simp add: union_assoc)
        also have " = mset (remdups a' @ x # removeAll x (remdups (list_diff b a')))"
          by (simp only: remdupsRemoveAllCommute)
        also have " = mset (remdups a') + mset (x # removeAll x (remdups (list_diff b a')))"
          by simp
        also have " = mset (remdups a') + {#x#} + mset (removeAll x (remdups (list_diff b a')))"
          by simp
        also have " = mset (remdups a') + mset (remdups (list_diff b a'))"
        proof-
          from x  set a' x  set b
          have "x  set (list_diff b a')"
            using listDiffIff[of "x" "b" "a'"]
            by simp
          hence "x  set (remdups (list_diff b a'))"
            by auto
          thus ?thesis
            using removeAll_multiset[of "remdups (list_diff b a')" "x"]
            by (simp add: union_assoc)
        qed
        also have " = mset (remdups (a' @ b))"
          using Cons(1)
          by simp
        also have " = mset (remdups ((x # a') @ b))"
          using x  set b
          by simp
        finally show ?thesis
          by simp
      qed
    next
      case False
      thus ?thesis
      proof-
        have "mset (remdups (x # a') @ remdups (list_diff b (x # a'))) = 
          mset (x # remdups a' @ remdups (list_diff b (x # a')))"
        proof-
          have "remdups (x # a') = x # remdups a'"
            using x  set a'
            by auto
          thus ?thesis
            by simp
        qed
        also have " = mset (x # remdups a' @ remdups (list_diff (removeAll x b) a'))"
          by auto
        also have " = mset (x # remdups a' @ remdups (list_diff b a'))"
          using x  set b
          using removeAll_id[of "x" "b"]
          by simp
        also have " = {#x#} + mset (remdups (a' @ b))"
          using Cons(1)
          by (simp add: union_commute)
        also have " = mset (remdups ((x # a') @ b))"
          using x  set a' x  set b
          by (auto simp add: union_commute)
        finally show ?thesis
          by simp
      qed
    qed
  qed
qed
 
lemma remdupsListDiff:
"remdups (list_diff a b) = list_diff (remdups a) (remdups b)"
proof(induct a)
  case Nil
  thus ?case
    by simp
next
  case (Cons x a')
  thus ?case
    using listDiffIff[of "x" "a'" "b"]
    by auto
qed

(*********************************************************)
(*                       Multiset                        *)
(*********************************************************)

(* Repetition of lemmas from Multiset.thy -
   neccessary for r which I do not know how to represent as order instance. *)

definition
"multiset_le a b r == a = b  (a, b)  mult r"

lemma multisetEmptyLeI:
  "multiset_le {#} a r"
unfolding multiset_le_def
using one_step_implies_mult[of "a" "{#}" r "{#}"]
by auto

lemma multisetUnionLessMono2:
shows
  "trans r  (b1, b2)  mult r  (a + b1, a + b2)  mult r"
unfolding mult_def
apply (erule trancl_induct)
apply (blast intro: mult1_union transI)
apply (blast intro: mult1_union transI trancl_trans)
done


lemma multisetUnionLessMono1:
shows
  "trans r  (a1, a2)  mult r  (a1 + b, a2 + b)  mult r"
  by (metis multisetUnionLessMono2 union_commute)


lemma multisetUnionLeMono2:
assumes
  "trans r"
  "multiset_le b1 b2 r"
shows
  "multiset_le (a + b1) (a + b2) r"
using assms
unfolding multiset_le_def
using multisetUnionLessMono2[of "r" "b1" "b2" "a"]
by auto

lemma multisetUnionLeMono1:
assumes
  "trans r"
  "multiset_le a1 a2 r"
shows
  "multiset_le (a1 + b) (a2 + b) r"
using assms
unfolding multiset_le_def
using multisetUnionLessMono1[of "r" "a1" "a2" "b"]
by auto

lemma multisetLeTrans:
assumes
  "trans r"
  "multiset_le x y r"
  "multiset_le y z r"
shows
  "multiset_le x z r"
using assms
unfolding multiset_le_def
unfolding mult_def
by (blast intro: trancl_trans)


lemma multisetUnionLeMono:
assumes
  "trans r"
  "multiset_le a1 a2 r"
  "multiset_le b1 b2 r"
shows
  "multiset_le (a1 + b1) (a2 + b2) r"
using assms
using multisetUnionLeMono1[of "r" "a1" "a2" "b1"]
using multisetUnionLeMono2[of "r" "b1" "b2" "a2"]
using multisetLeTrans[of "r" "a1 + b1" "a2 + b1" "a2 + b2"]
by simp

lemma multisetLeListDiff:
assumes
  "trans r"
shows 
  "multiset_le (mset (list_diff a b)) (mset a) r"
proof (induct a)
  case Nil
  thus ?case
    unfolding multiset_le_def
    by simp
next
  case (Cons x a')
  thus ?case
    using assms
    using multisetEmptyLeI[of "{#x#}" "r"]
    using multisetUnionLeMono[of "r" "mset (list_diff a' b)" "mset a'" "{#}" "{#x#}"]
    using multisetUnionLeMono1[of "r" "mset (list_diff a' b)" "mset a'" "{#x#}"]
    by auto
qed

(*********************************************************)
(*                       Levi                            *)
(*********************************************************)
subsection‹Levi's lemma›

text‹Obsolete: these two lemmas are already proved as @{term
append_eq_append_conv2} and @{term append_eq_Cons_conv}.›

lemma FullLevi: 
  shows "(x @ y = z @ w) = 
                (x = z  y = w  
                ( t. z @ t = x  t @ y = w)  
                ( t. x @ t = z  t @ w = y))" (is "?lhs = ?rhs")
proof
  assume "?rhs"
  thus "?lhs"
    by auto
next
  assume "?lhs"
  thus "?rhs"
  proof (induct x arbitrary: z)
    case (Cons a x')
    show ?case
    proof (cases "z = []")
      case True
      with (a # x') @ y = z @ w
      obtain t where "z @ t = a # x'" "t @ y = w"
        by auto
      thus ?thesis
        by auto
    next
      case False
      then obtain b and z' where "z = b # z'"
        by (auto simp add: neq_Nil_conv)
      with (a # x') @ y = z @ w
      have "x' @ y = z' @ w" "a = b"
        by auto
      with Cons(1)[of "z'"]
      have "x' = z'  y = w  (t. z' @ t = x'  t @ y = w)  (t. x' @ t = z'  t @ w = y)"
        by simp
      with a = b z = b # z' 
      show ?thesis
        by auto
    qed
  qed simp
qed

lemma SimpleLevi:
  shows "(p @ s = a # list) = 
             ( p = []  s = a # list  
              ( t. p = a # t  t @ s = list))"
by (induct p) auto

subsection‹Single element lists›
lemma lengthOneCharacterisation:
  shows "(length l = 1) = (l = [hd l])"
by (induct l) auto

lemma lengthOneImpliesOnlyElement:
  assumes "length l = 1" and "a : set l"
  shows " a'. a' : set l  a' = a"
proof (cases l) 
  case (Cons literal' clause')
  with assms 
  show ?thesis 
    by auto
qed simp


end

Theory CNF

(*    Title:              SATSolver/CNF.thy
      Author:             Filip Maric
      Maintainer:         Filip Maric <filip at matf.bg.ac.yu>
*)

section ‹CNF›
theory CNF
imports MoreList
begin
text‹Theory describing formulae in Conjunctive Normal Form.›


(********************************************************************)
subsection‹Syntax›
(********************************************************************)

(*------------------------------------------------------------------*)
subsubsection‹Basic datatypes›
type_synonym Variable  = nat
datatype Literal = Pos Variable | Neg Variable
type_synonym Clause = "Literal list"
type_synonym Formula = "Clause list"

text‹Notice that instead of set or multisets, lists are used in
definitions of clauses and formulae. This is done because SAT solver
implementation usually use list-like data structures for representing
these datatypes.›

(*------------------------------------------------------------------*)
subsubsection‹Membership›

text‹Check if the literal is member of a clause, clause is a member 
  of a formula or the literal is a member of a formula›
consts member  :: "'a  'b  bool" (infixl "el" 55)

overloading literalElClause  "member :: Literal  Clause  bool"
begin
  definition [simp]: "((literal::Literal) el (clause::Clause)) == literal  set clause"
end

overloading clauseElFormula  "member :: Clause  Formula  bool"
begin
  definition [simp]: "((clause::Clause) el (formula::Formula)) == clause  set formula"
end

overloading el_literal  "(el) :: Literal  Formula  bool"
begin

primrec el_literal where
"(literal::Literal) el ([]::Formula) = False" |
"((literal::Literal) el ((clause # formula)::Formula)) = ((literal el clause)  (literal el formula))"

end

lemma literalElFormulaCharacterization:
  fixes literal :: Literal and formula :: Formula
  shows "(literal el formula) = ( (clause::Clause). clause el formula  literal el clause)"
by (induct formula) auto


(*------------------------------------------------------------------*)
subsubsection‹Variables›

text‹The variable of a given literal›
primrec 
var      :: "Literal  Variable"
where 
  "var (Pos v) = v"
| "var (Neg v) = v"

text‹Set of variables of a given clause, formula or valuation›
primrec
varsClause :: "(Literal list)  (Variable set)"
where
  "varsClause [] = {}"
| "varsClause (literal # list) = {var literal}  (varsClause list)"

primrec
varsFormula :: "Formula  (Variable set)"
where
  "varsFormula [] = {}"
| "varsFormula (clause # formula) = (varsClause clause)  (varsFormula formula)"

consts vars :: "'a  Variable set"

overloading vars_clause  "vars :: Clause  Variable set"
begin
  definition [simp]: "vars (clause::Clause) == varsClause clause"
end

overloading vars_formula  "vars :: Formula  Variable set"
begin
  definition [simp]: "vars (formula::Formula) == varsFormula formula"
end

overloading vars_set  "vars :: Literal set  Variable set"
begin
  definition [simp]: "vars (s::Literal set) == {vbl.  l. l  s  var l = vbl}"
end

lemma clauseContainsItsLiteralsVariable: 
  fixes literal :: Literal and clause :: Clause
  assumes "literal el clause"
  shows "var literal  vars clause"
using assms
by (induct clause) auto

lemma formulaContainsItsLiteralsVariable:
  fixes literal :: Literal and formula::Formula
  assumes "literal el formula" 
  shows "var literal  vars formula"
using assms
proof (induct formula)
  case Nil
  thus ?case 
    by simp
next
  case (Cons clause formula)
  thus ?case
  proof (cases "literal el clause")
    case True
    with clauseContainsItsLiteralsVariable
    have "var literal  vars clause" 
      by simp
    thus ?thesis 
      by simp
  next
    case False
    with Cons
    show ?thesis 
      by simp
  qed
qed

lemma formulaContainsItsClausesVariables:
  fixes clause :: Clause and formula :: Formula
  assumes "clause el formula"
  shows "vars clause  vars formula"
using assms
by (induct formula) auto

lemma varsAppendFormulae:
  fixes formula1 :: Formula and formula2 :: Formula
  shows "vars (formula1 @ formula2) = vars formula1  vars formula2"
by (induct formula1) auto

lemma varsAppendClauses:
  fixes clause1 :: Clause and clause2 :: Clause
  shows "vars (clause1 @ clause2) = vars clause1  vars clause2"
by (induct clause1) auto

lemma varsRemoveLiteral:
  fixes literal :: Literal and clause :: Clause
  shows "vars (removeAll literal clause)  vars clause"
by (induct clause) auto

lemma varsRemoveLiteralSuperset:
  fixes literal :: Literal and clause :: Clause
  shows "vars clause - {var literal}   vars (removeAll literal clause)"
by (induct clause) auto

lemma varsRemoveAllClause:
  fixes clause :: Clause and formula :: Formula
  shows "vars (removeAll clause formula)  vars formula"
by (induct formula) auto

lemma varsRemoveAllClauseSuperset:
  fixes clause :: Clause and formula :: Formula
  shows "vars formula - vars clause  vars (removeAll clause formula)"
by (induct formula) auto

lemma varInClauseVars:
  fixes variable :: Variable and clause :: Clause
  shows "variable  vars clause = ( literal. literal el clause  var literal = variable)"
by (induct clause) auto

lemma varInFormulaVars: 
  fixes variable :: Variable and formula :: Formula
  shows "variable  vars formula = ( literal. literal el formula  var literal = variable)" (is "?lhs formula = ?rhs formula")
proof (induct formula)
  case Nil
  show ?case 
    by simp
next
  case (Cons clause formula)
  show ?case
  proof
    assume P: "?lhs (clause # formula)"
    thus "?rhs (clause # formula)"
    proof (cases "variable  vars clause")
      case True
      with varInClauseVars 
      have " literal. literal el clause  var literal = variable" 
        by simp
      thus ?thesis 
        by auto
    next
      case False
      with P 
      have "variable  vars formula" 
        by simp
      with Cons
      show ?thesis 
        by auto
    qed
  next
    assume "?rhs (clause # formula)"
    then obtain l 
      where lEl: "l el clause # formula" and varL:"var l = variable" 
      by auto
    from lEl formulaContainsItsLiteralsVariable [of "l" "clause # formula"] 
    have "var l  vars (clause # formula)" 
      by auto
    with varL 
    show "?lhs (clause # formula)" 
      by simp
  qed
qed

lemma varsSubsetFormula:
  fixes F :: Formula and F' :: Formula
  assumes " c::Clause. c el F  c el F'"
  shows "vars F  vars F'"
using assms
proof (induct F)
  case Nil
  thus ?case
    by simp
next
  case (Cons c' F'')
  thus ?case
    using formulaContainsItsClausesVariables[of "c'" "F'"]
    by simp
qed

lemma varsClauseVarsSet:
fixes 
  clause :: Clause
shows
  "vars clause = vars (set clause)"
by (induct clause) auto


(*------------------------------------------------------------------*)
subsubsection‹Opposite literals›

primrec
opposite :: "Literal  Literal"
where
  "opposite (Pos v) = (Neg v)"
| "opposite (Neg v) = (Pos v)"

lemma oppositeIdempotency [simp]:
  fixes literal::Literal
  shows "opposite (opposite literal) = literal"
by (induct literal) auto

lemma oppositeSymmetry [simp]:
  fixes literal1::Literal and literal2::Literal
  shows "(opposite literal1 = literal2) = (opposite literal2 = literal1)"
by auto

lemma oppositeUniqueness [simp]:
  fixes literal1::Literal and literal2::Literal
  shows "(opposite literal1 = opposite literal2) = (literal1 = literal2)"
proof
  assume "opposite literal1 = opposite literal2"
  hence "opposite (opposite literal1) = opposite (opposite literal2)" 
    by simp
  thus "literal1 = literal2" 
    by simp 
qed simp

lemma oppositeIsDifferentFromLiteral [simp]:
  fixes literal::Literal
  shows "opposite literal  literal"
by (induct literal) auto

lemma oppositeLiteralsHaveSameVariable [simp]:
  fixes literal::Literal
  shows "var (opposite literal) = var literal"
by (induct literal) auto

lemma literalsWithSameVariableAreEqualOrOpposite:
  fixes literal1::Literal and literal2::Literal
  shows "(var literal1 = var literal2) = (literal1 = literal2  opposite literal1 = literal2)" (is "?lhs = ?rhs")
proof
  assume ?lhs
  show ?rhs
  proof (cases literal1)
    case "Pos"
    note Pos1 = this
    show ?thesis
    proof (cases literal2)
      case "Pos"
      with ?lhs Pos1 show ?thesis 
        by simp
    next
      case "Neg"
      with ?lhs Pos1 show ?thesis 
        by simp
    qed
  next
    case "Neg"
    note Neg1 = this
    show ?thesis
    proof (cases literal2)
      case "Pos"
      with ?lhs Neg1 show ?thesis 
        by simp
    next
      case "Neg"
      with ?lhs Neg1 show ?thesis 
        by simp
    qed
  qed
next
  assume ?rhs
  thus ?lhs 
    by auto
qed

text‹The list of literals obtained by negating all literals of a
literal list (clause, valuation). Notice that this is not a negation 
of a clause, because the negation of a clause is a conjunction and 
not a disjunction.›
definition
oppositeLiteralList :: "Literal list  Literal list"
where
"oppositeLiteralList clause == map opposite clause"

lemma literalElListIffOppositeLiteralElOppositeLiteralList: 
  fixes literal :: Literal and literalList :: "Literal list"
  shows "literal el literalList = (opposite literal) el (oppositeLiteralList literalList)"
unfolding oppositeLiteralList_def
proof (induct literalList)
  case Nil
  thus ?case
    by simp
next
  case (Cons l literalLlist')
  show ?case
  proof (cases "l = literal")
    case True
    thus ?thesis
      by simp
  next
    case False
    thus ?thesis
      by auto
  qed
qed

lemma oppositeLiteralListIdempotency [simp]: 
  fixes literalList :: "Literal list"
  shows "oppositeLiteralList (oppositeLiteralList literalList) = literalList"
unfolding oppositeLiteralList_def
by (induct literalList) auto

lemma oppositeLiteralListRemove: 
  fixes literal :: Literal and literalList :: "Literal list"
  shows "oppositeLiteralList (removeAll literal literalList) = removeAll (opposite literal) (oppositeLiteralList literalList)"
unfolding oppositeLiteralList_def
by (induct literalList) auto

lemma oppositeLiteralListNonempty:
  fixes literalList :: "Literal list"
  shows "(literalList  []) = ((oppositeLiteralList literalList)  [])"
unfolding oppositeLiteralList_def
by (induct literalList) auto

lemma varsOppositeLiteralList:
shows "vars (oppositeLiteralList clause) = vars clause"
unfolding oppositeLiteralList_def
by (induct clause) auto


(*------------------------------------------------------------------*)
subsubsection‹Tautological clauses›

text‹Check if the clause contains both a literal and its opposite›
primrec
clauseTautology :: "Clause  bool"
where
  "clauseTautology [] = False"
| "clauseTautology (literal # clause) = (opposite literal el clause  clauseTautology clause)"

lemma clauseTautologyCharacterization: 
  fixes clause :: Clause
  shows "clauseTautology clause = ( literal. literal el clause  (opposite literal) el clause)"
by (induct clause) auto


(********************************************************************)
subsection‹Semantics›
(********************************************************************)

(*------------------------------------------------------------------*)
subsubsection‹Valuations›

type_synonym Valuation = "Literal list"

lemma valuationContainsItsLiteralsVariable: 
  fixes literal :: Literal and valuation :: Valuation
  assumes "literal el valuation"
  shows "var literal  vars valuation"
using assms
by (induct valuation) auto

lemma varsSubsetValuation: 
  fixes valuation1 :: Valuation and valuation2 :: Valuation
  assumes "set valuation1   set valuation2"
  shows "vars valuation1  vars valuation2"
using assms
proof (induct valuation1)
  case Nil
  show ?case 
    by simp
next
  case (Cons literal valuation)
  note caseCons = this
  hence "literal el valuation2" 
    by auto
  with valuationContainsItsLiteralsVariable [of "literal" "valuation2"]
  have "var literal  vars valuation2" .
  with caseCons 
  show ?case 
    by simp
qed

lemma varsAppendValuation:
  fixes valuation1 :: Valuation and valuation2 :: Valuation
  shows "vars (valuation1 @ valuation2) = vars valuation1  vars valuation2"
by (induct valuation1) auto
lemma varsPrefixValuation:
  fixes valuation1 :: Valuation and valuation2 :: Valuation
  assumes "isPrefix valuation1 valuation2"
  shows "vars valuation1  vars valuation2"
proof-
  from assms 
  have "set valuation1  set valuation2"
    by (auto simp add:isPrefix_def)
  thus ?thesis
    by (rule varsSubsetValuation)
qed

(*------------------------------------------------------------------*)
subsubsection‹True/False literals›

text‹Check if the literal is contained in the given valuation›
definition literalTrue     :: "Literal  Valuation  bool"
where
literalTrue_def [simp]: "literalTrue literal valuation == literal el valuation"

text‹Check if the opposite literal is contained in the given valuation›
definition literalFalse    :: "Literal  Valuation  bool"
where
literalFalse_def [simp]: "literalFalse literal valuation == opposite literal el valuation"


lemma variableDefinedImpliesLiteralDefined:
  fixes literal :: Literal and valuation :: Valuation
  shows "var literal  vars valuation = (literalTrue literal valuation  literalFalse literal valuation)" 
    (is "(?lhs valuation) = (?rhs valuation)")
proof
  assume "?rhs valuation"
  thus "?lhs valuation" 
  proof
    assume "literalTrue literal valuation"
    hence "literal el valuation" 
      by simp
    thus ?thesis
      using valuationContainsItsLiteralsVariable[of "literal" "valuation"] 
      by simp
  next
    assume "literalFalse literal valuation"
    hence "opposite literal el valuation" 
      by simp
    thus ?thesis
      using valuationContainsItsLiteralsVariable[of "opposite literal" "valuation"] 
      by simp
  qed
next
  assume "?lhs valuation" 
  thus "?rhs valuation"
  proof (induct valuation)
    case Nil
    thus ?case 
      by simp
  next
    case (Cons literal' valuation')
    note ih=this
    show ?case
    proof (cases "var literal  vars valuation'")
      case True
      with ih 
      show "?rhs (literal' # valuation')" 
        by auto
    next
      case False
      with ih 
      have "var literal' = var literal" 
        by simp
      hence "literal' = literal  opposite literal' = literal"
        by (simp add:literalsWithSameVariableAreEqualOrOpposite)
      thus "?rhs (literal' # valuation')" 
        by auto
    qed
  qed
qed

(*------------------------------------------------------------------*)
subsubsection‹True/False clauses›

text‹Check if there is a literal from the clause which is true in the given valuation›
primrec
clauseTrue      :: "Clause  Valuation  bool"
where
  "clauseTrue [] valuation = False"
| "clauseTrue (literal # clause) valuation = (literalTrue literal valuation  clauseTrue clause valuation)"

text‹Check if all the literals from the clause are false in the given valuation›
primrec
clauseFalse     :: "Clause  Valuation  bool"
where
  "clauseFalse [] valuation = True"
| "clauseFalse (literal # clause) valuation = (literalFalse literal valuation  clauseFalse clause valuation)"


lemma clauseTrueIffContainsTrueLiteral: 
  fixes clause :: Clause and valuation :: Valuation  
  shows "clauseTrue clause valuation = ( literal. literal el clause  literalTrue literal valuation)"
by (induct clause) auto

lemma clauseFalseIffAllLiteralsAreFalse:
  fixes clause :: Clause and valuation :: Valuation  
  shows "clauseFalse clause valuation = ( literal. literal el clause  literalFalse literal valuation)"
by (induct clause) auto

lemma clauseFalseRemove:
  assumes "clauseFalse clause valuation"
  shows "clauseFalse (removeAll literal clause) valuation"
proof-
  {
    fix l::Literal
    assume "l el removeAll literal clause"
    hence "l el clause"
      by simp
   with ‹clauseFalse clause valuation 
   have "literalFalse l valuation"
     by (simp add:clauseFalseIffAllLiteralsAreFalse)
  }
  thus ?thesis
    by (simp add:clauseFalseIffAllLiteralsAreFalse)
qed

lemma clauseFalseAppendValuation: 
  fixes clause :: Clause and valuation :: Valuation and valuation' :: Valuation
  assumes "clauseFalse clause valuation"
  shows "clauseFalse clause (valuation @ valuation')"
using assms
by (induct clause) auto

lemma clauseTrueAppendValuation:
  fixes clause :: Clause and valuation :: Valuation and valuation' :: Valuation
  assumes "clauseTrue clause valuation"
  shows "clauseTrue clause (valuation @ valuation')"
using assms
by (induct clause) auto

lemma emptyClauseIsFalse:
  fixes valuation :: Valuation
  shows "clauseFalse [] valuation"
by auto

lemma emptyValuationFalsifiesOnlyEmptyClause:
  fixes clause :: Clause
  assumes "clause  []"
  shows "¬  clauseFalse clause []"
using assms
by (induct clause) auto
  

lemma valuationContainsItsFalseClausesVariables:
  fixes clause::Clause and valuation::Valuation
  assumes "clauseFalse clause valuation"
  shows "vars clause  vars valuation"
proof
  fix v::Variable
  assume "v  vars clause"
  hence " l. var l = v  l el clause"
    by (induct clause) auto
  then obtain l 
    where "var l = v" "l el clause"
    by auto
  from l el clause ‹clauseFalse clause valuation
  have "literalFalse l valuation"
    by (simp add: clauseFalseIffAllLiteralsAreFalse)
  with ‹var l = v 
  show "v  vars valuation"
    using valuationContainsItsLiteralsVariable[of "opposite l"]
    by simp
qed
  

(*------------------------------------------------------------------*)
subsubsection‹True/False formulae›

text‹Check if all the clauses from the formula are false in the given valuation›
primrec
formulaTrue     :: "Formula  Valuation  bool"
where
  "formulaTrue [] valuation = True"
| "formulaTrue (clause # formula) valuation = (clauseTrue clause valuation  formulaTrue formula valuation)"

text‹Check if there is a clause from the formula which is false in the given valuation›
primrec
formulaFalse    :: "Formula  Valuation  bool"
where
  "formulaFalse [] valuation = False"
| "formulaFalse (clause # formula) valuation = (clauseFalse clause valuation  formulaFalse formula valuation)"


lemma formulaTrueIffAllClausesAreTrue: 
  fixes formula :: Formula and valuation :: Valuation
  shows "formulaTrue formula valuation = ( clause. clause el formula  clauseTrue clause valuation)"
by (induct formula) auto

lemma formulaFalseIffContainsFalseClause: 
  fixes formula :: Formula and valuation :: Valuation
  shows "formulaFalse formula valuation = ( clause. clause el formula  clauseFalse clause valuation)"
by (induct formula) auto

lemma formulaTrueAssociativity:
  fixes f1 :: Formula and f2 :: Formula and f3 :: Formula and valuation :: Valuation
  shows "formulaTrue ((f1 @ f2) @ f3) valuation = formulaTrue (f1 @ (f2 @ f3)) valuation"
by (auto simp add:formulaTrueIffAllClausesAreTrue)

lemma formulaTrueCommutativity:
  fixes f1 :: Formula and f2 :: Formula and valuation :: Valuation
  shows "formulaTrue (f1 @ f2) valuation = formulaTrue (f2 @ f1) valuation"
by (auto simp add:formulaTrueIffAllClausesAreTrue)

lemma formulaTrueSubset:
  fixes formula :: Formula and formula' :: Formula and valuation :: Valuation
  assumes 
  formulaTrue: "formulaTrue formula valuation" and
  subset: " (clause::Clause). clause el formula'  clause el formula"
  shows "formulaTrue formula' valuation"
proof -
  {
    fix clause :: Clause
    assume "clause el formula'"
    with formulaTrue subset 
    have "clauseTrue clause valuation"
      by (simp add:formulaTrueIffAllClausesAreTrue)
  }
  thus ?thesis
    by (simp add:formulaTrueIffAllClausesAreTrue)
qed

lemma formulaTrueAppend:
  fixes formula1 :: Formula and formula2 :: Formula and valuation :: Valuation
  shows "formulaTrue (formula1 @ formula2) valuation = (formulaTrue formula1 valuation  formulaTrue formula2 valuation)"
by (induct formula1) auto

lemma formulaTrueRemoveAll:
  fixes formula :: Formula and clause :: Clause and valuation :: Valuation    
  assumes "formulaTrue formula valuation"
  shows "formulaTrue (removeAll clause formula) valuation"
using assms
by (induct formula) auto

lemma formulaFalseAppend: 
  fixes formula :: Formula and formula' :: Formula and valuation :: Valuation  
  assumes "formulaFalse formula valuation"
  shows "formulaFalse (formula @ formula') valuation"
using assms 
by (induct formula) auto

lemma formulaTrueAppendValuation: 
  fixes formula :: Formula and valuation :: Valuation and valuation' :: Valuation
  assumes "formulaTrue formula valuation"
  shows "formulaTrue formula (valuation @ valuation')"
using assms
by (induct formula) (auto simp add:clauseTrueAppendValuation)

lemma formulaFalseAppendValuation: 
  fixes formula :: Formula and valuation :: Valuation and valuation' :: Valuation
  assumes "formulaFalse formula valuation"
  shows "formulaFalse formula (valuation @ valuation')"
using assms
by (induct formula) (auto simp add:clauseFalseAppendValuation)

lemma trueFormulaWithSingleLiteralClause:
  fixes formula :: Formula and literal :: Literal and valuation :: Valuation
  assumes "formulaTrue (removeAll [literal] formula) (valuation @ [literal])"
  shows "formulaTrue formula (valuation @ [literal])"
proof -
  {
    fix clause :: Clause
    assume "clause el formula"
    with assms 
    have "clauseTrue clause (valuation @ [literal])"
    proof (cases "clause = [literal]")
      case True
      thus ?thesis
        by simp
    next
      case False
      with clause el formula
      have "clause el (removeAll [literal] formula)"
        by simp
      with ‹formulaTrue (removeAll [literal] formula) (valuation @ [literal]) 
      show ?thesis
        by (simp add: formulaTrueIffAllClausesAreTrue)
    qed
  }
  thus ?thesis
    by (simp add: formulaTrueIffAllClausesAreTrue)
qed

(*------------------------------------------------------------------*)
subsubsection‹Valuation viewed as a formula›

text‹Converts a valuation (the list of literals) into formula (list of single member lists of literals)›
primrec
val2form    :: "Valuation  Formula"
where
  "val2form [] = []"
| "val2form (literal # valuation) = [literal] # val2form valuation"

lemma val2FormEl: 
  fixes literal :: Literal and valuation :: Valuation 
  shows "literal el valuation = [literal] el val2form valuation"
by (induct valuation) auto

lemma val2FormAreSingleLiteralClauses: 
  fixes clause :: Clause and valuation :: Valuation
  shows "clause el val2form valuation  ( literal. clause = [literal]  literal el valuation)"
by (induct valuation) auto

lemma val2formOfSingleLiteralValuation:
assumes "length v = 1"
shows "val2form v = [[hd v]]"
using assms
by (induct v) auto

lemma val2FormRemoveAll: 
  fixes literal :: Literal and valuation :: Valuation 
  shows "removeAll [literal] (val2form valuation) = val2form (removeAll literal valuation)"
by (induct valuation) auto

lemma val2formAppend: 
  fixes valuation1 :: Valuation and valuation2 :: Valuation
  shows "val2form (valuation1 @ valuation2) = (val2form valuation1 @ val2form valuation2)"
by (induct valuation1) auto

lemma val2formFormulaTrue: 
  fixes valuation1 :: Valuation and valuation2 :: Valuation
  shows "formulaTrue (val2form valuation1) valuation2 = ( (literal :: Literal). literal el valuation1  literal el valuation2)"
by (induct valuation1) auto


(*------------------------------------------------------------------*)
subsubsection‹Consistency of valuations›

text‹Valuation is inconsistent if it contains both a literal and its opposite.›
primrec
inconsistent   :: "Valuation  bool"
where
  "inconsistent [] = False"
| "inconsistent (literal # valuation) = (opposite literal el valuation  inconsistent valuation)"
definition [simp]: "consistent valuation == ¬ inconsistent valuation"

lemma inconsistentCharacterization: 
  fixes valuation :: Valuation
  shows "inconsistent valuation = ( literal. literalTrue literal valuation  literalFalse literal valuation)"
by (induct valuation) auto

lemma clauseTrueAndClauseFalseImpliesInconsistent: 
  fixes clause :: Clause and valuation :: Valuation
  assumes "clauseTrue clause valuation" and "clauseFalse clause valuation"
  shows "inconsistent valuation"
proof -
  from ‹clauseTrue clause valuation obtain literal :: Literal 
    where "literal el clause" and "literalTrue literal valuation"
    by (auto simp add: clauseTrueIffContainsTrueLiteral)
  with ‹clauseFalse clause valuation 
  have "literalFalse literal valuation" 
    by (auto simp add: clauseFalseIffAllLiteralsAreFalse)
  from ‹literalTrue literal valuation ‹literalFalse literal valuation 
  show ?thesis 
    by (auto simp add: inconsistentCharacterization)
qed

lemma formulaTrueAndFormulaFalseImpliesInconsistent: 
  fixes formula :: Formula and valuation :: Valuation
  assumes "formulaTrue formula valuation" and "formulaFalse formula valuation"
  shows "inconsistent valuation"
proof -
  from ‹formulaFalse formula valuation obtain clause :: Clause 
    where "clause el formula" and "clauseFalse clause valuation"
    by (auto simp add: formulaFalseIffContainsFalseClause)
  with ‹formulaTrue formula valuation 
  have "clauseTrue clause valuation" 
    by (auto simp add: formulaTrueIffAllClausesAreTrue)
  from ‹clauseTrue clause valuation ‹clauseFalse clause valuation 
  show ?thesis 
    by (auto simp add: clauseTrueAndClauseFalseImpliesInconsistent)
qed

lemma inconsistentAppend:
  fixes valuation1 :: Valuation and valuation2 :: Valuation
  assumes "inconsistent (valuation1 @ valuation2)"
  shows "inconsistent valuation1  inconsistent valuation2  ( literal. literalTrue literal valuation1  literalFalse literal valuation2)"
using assms
proof (cases "inconsistent valuation1")
  case True
  thus ?thesis 
    by simp
next
  case False
  thus ?thesis
  proof (cases "inconsistent valuation2")
    case True
    thus ?thesis 
      by simp
  next
    case False
    from ‹inconsistent (valuation1 @ valuation2) obtain literal :: Literal 
      where "literalTrue literal (valuation1 @ valuation2)" and "literalFalse literal (valuation1 @ valuation2)"
      by (auto simp add:inconsistentCharacterization)
    hence "( literal. literalTrue literal valuation1  literalFalse literal valuation2)"
    proof (cases "literalTrue literal valuation1")
      case True
      with ¬ inconsistent valuation1 
      have "¬ literalFalse literal valuation1" 
        by (auto simp add:inconsistentCharacterization)
      with ‹literalFalse literal (valuation1 @ valuation2) 
      have "literalFalse literal valuation2" 
        by auto
      with True 
      show ?thesis 
        by auto
    next
      case False
      with ‹literalTrue literal (valuation1 @ valuation2) 
      have "literalTrue literal valuation2"
        by auto
      with ¬ inconsistent valuation2 
      have "¬ literalFalse literal valuation2"
        by (auto simp add:inconsistentCharacterization)
      with ‹literalFalse literal (valuation1 @ valuation2) 
      have "literalFalse literal valuation1"
        by auto
      with ‹literalTrue literal valuation2
      show ?thesis 
        by auto
    qed
    thus ?thesis 
      by simp
  qed
qed

lemma consistentAppendElement:
assumes "consistent v" and "¬ literalFalse l v"
shows "consistent (v @ [l])"
proof-
  {
    assume "¬ ?thesis"
    with ‹consistent v
    have "(opposite l) el v"
      using inconsistentAppend[of "v" "[l]"]
      by auto
    with ¬ literalFalse l v
    have False
      by simp
  }
  thus ?thesis
    by auto
qed

lemma inconsistentRemoveAll:
  fixes literal :: Literal and valuation :: Valuation
  assumes "inconsistent (removeAll literal valuation)" 
  shows "inconsistent valuation"
using assms
proof -
  from ‹inconsistent (removeAll literal valuation) obtain literal' :: Literal 
    where l'True: "literalTrue literal' (removeAll literal valuation)" and l'False: "literalFalse literal' (removeAll literal valuation)"
    by (auto simp add:inconsistentCharacterization)
  from l'True 
  have "literalTrue literal' valuation"
    by simp
  moreover
  from l'False 
  have "literalFalse literal' valuation"
    by simp
  ultimately
  show ?thesis 
    by (auto simp add:inconsistentCharacterization)
qed

lemma inconsistentPrefix: 
  assumes "isPrefix valuation1 valuation2" and "inconsistent valuation1"
  shows "inconsistent valuation2"
using assms
by (auto simp add:inconsistentCharacterization isPrefix_def)

lemma consistentPrefix:
  assumes "isPrefix valuation1 valuation2" and "consistent valuation2"
  shows "consistent valuation1"
using assms
by (auto simp add:inconsistentCharacterization isPrefix_def)


(*------------------------------------------------------------------*)
subsubsection‹Totality of valuations›

text‹Checks if the valuation contains all the variables from the given set of variables›
definition total where
[simp]: "total valuation variables == variables  vars valuation"

lemma totalSubset: 
  fixes A :: "Variable set" and B :: "Variable set" and valuation :: "Valuation"
  assumes "A  B" and "total valuation B"
  shows "total valuation A"
using assms
by auto

lemma totalFormulaImpliesTotalClause:
  fixes clause :: Clause and formula :: Formula and valuation :: Valuation
  assumes clauseEl: "clause el formula" and totalFormula: "total valuation (vars formula)"
  shows totalClause: "total valuation (vars clause)"
proof -
  from clauseEl 
  have "vars clause  vars formula" 
    using formulaContainsItsClausesVariables [of "clause" "formula"] 
    by simp
  with totalFormula 
  show ?thesis 
    by (simp add: totalSubset)
qed

lemma totalValuationForClauseDefinesAllItsLiterals:
  fixes clause :: Clause and valuation :: Valuation and literal :: Literal
  assumes 
  totalClause: "total valuation (vars clause)" and
  literalEl: "literal el clause"
  shows trueOrFalse: "literalTrue literal valuation  literalFalse literal valuation"
proof -
  from literalEl 
  have "var literal  vars clause"
    using clauseContainsItsLiteralsVariable 
    by auto
  with totalClause 
  have "var literal  vars valuation" 
    by auto
  thus ?thesis 
    using  variableDefinedImpliesLiteralDefined [of "literal" "valuation"] 
    by simp
qed

lemma totalValuationForClauseDefinesItsValue:
  fixes clause :: Clause and valuation :: Valuation
  assumes totalClause: "total valuation (vars clause)"
  shows "clauseTrue clause valuation  clauseFalse clause valuation"
proof (cases "clauseFalse clause valuation")
  case True
  thus ?thesis 
    by (rule disjI2)
next
  case False
  hence "¬ ( l. l el clause  literalFalse l valuation)" 
    by (auto simp add:clauseFalseIffAllLiteralsAreFalse)
  then obtain l :: Literal 
    where "l el clause" and "¬ literalFalse l valuation" 
    by auto
  with totalClause 
  have "literalTrue l valuation  literalFalse l valuation"
    using totalValuationForClauseDefinesAllItsLiterals [of "valuation" "clause" "l"] 
    by auto
  with ¬ literalFalse l valuation 
  have "literalTrue l valuation" 
    by simp
  with l el clause 
  have "(clauseTrue clause valuation)" 
    by (auto simp add:clauseTrueIffContainsTrueLiteral)
  thus ?thesis 
    by (rule disjI1) 
qed

lemma totalValuationForFormulaDefinesAllItsLiterals: 
  fixes formula::Formula and valuation::Valuation
  assumes totalFormula: "total valuation (vars formula)" and
  literalElFormula: "literal el formula"
  shows "literalTrue literal valuation  literalFalse literal valuation"
proof -
  from literalElFormula 
  have "var literal  vars formula" 
    by (rule formulaContainsItsLiteralsVariable)
  with totalFormula 
  have "var literal  vars valuation" 
    by auto
  thus ?thesis using variableDefinedImpliesLiteralDefined [of "literal" "valuation"] 
    by simp
qed

lemma totalValuationForFormulaDefinesAllItsClauses:
  fixes formula :: Formula and valuation :: Valuation and clause :: Clause
  assumes totalFormula: "total valuation (vars formula)" and 
  clauseElFormula: "clause el formula" 
  shows "clauseTrue clause valuation  clauseFalse clause valuation"
proof -
  from clauseElFormula totalFormula 
  have "total valuation (vars clause)"
    by (rule totalFormulaImpliesTotalClause)
  thus ?thesis
    by (rule totalValuationForClauseDefinesItsValue)
qed

lemma totalValuationForFormulaDefinesItsValue:
  assumes totalFormula: "total valuation (vars formula)"
  shows "formulaTrue formula valuation  formulaFalse formula valuation"
proof (cases "formulaTrue formula valuation")
  case True
  thus ?thesis
    by simp
next
  case False
  then obtain clause :: Clause 
    where clauseElFormula: "clause el formula" and notClauseTrue: "¬ clauseTrue clause valuation" 
    by (auto simp add: formulaTrueIffAllClausesAreTrue)
  from clauseElFormula totalFormula
  have "total valuation (vars clause)"
    using totalFormulaImpliesTotalClause [of "clause" "formula" "valuation"]
    by simp
  with notClauseTrue 
  have "clauseFalse clause valuation" 
    using totalValuationForClauseDefinesItsValue [of "valuation" "clause"]
    by simp
  with clauseElFormula 
  show ?thesis 
    by (auto simp add:formulaFalseIffContainsFalseClause)
qed

lemma totalRemoveAllSingleLiteralClause:
  fixes literal :: Literal and valuation :: Valuation and formula :: Formula
  assumes varLiteral: "var literal  vars valuation" and totalRemoveAll: "total valuation (vars (removeAll [literal] formula))"
  shows "total valuation (vars formula)"
proof -
  have "vars formula - vars [literal]  vars (removeAll [literal] formula)"
    by (rule varsRemoveAllClauseSuperset)
  with assms 
  show ?thesis 
    by auto
qed


(*------------------------------------------------------------------*)
subsubsection‹Models and satisfiability›

text‹Model of a formula is a consistent valuation under which formula/clause is true›
consts model :: "Valuation  'a  bool"

overloading modelFormula  "model :: Valuation  Formula  bool"
begin
  definition [simp]: "model valuation (formula::Formula) ==
    consistent valuation  (formulaTrue formula valuation)"
end

overloading modelClause  "model :: Valuation  Clause  bool"
begin
  definition [simp]: "model valuation (clause::Clause) ==
    consistent valuation  (clauseTrue clause valuation)"
end

text‹Checks if a formula has a model›
definition satisfiable :: "Formula  bool"
where
"satisfiable formula ==  valuation. model valuation formula"

lemma formulaWithEmptyClauseIsUnsatisfiable:
  fixes formula :: Formula
  assumes "([]::Clause) el formula"
  shows "¬ satisfiable formula"
using assms
by (auto simp add: satisfiable_def formulaTrueIffAllClausesAreTrue)

lemma satisfiableSubset: 
  fixes formula0 :: Formula and formula :: Formula
  assumes subset: " (clause::Clause). clause el formula0  clause el formula"
  shows  "satisfiable formula  satisfiable formula0"
proof
  assume "satisfiable formula"
  show "satisfiable formula0"
  proof -
    from ‹satisfiable formula obtain valuation :: Valuation
      where "model valuation formula" 
      by (auto simp add: satisfiable_def)
    {
      fix clause :: Clause
      assume "clause el formula0"
      with subset 
      have "clause el formula" 
        by simp
      with ‹model valuation formula 
      have "clauseTrue clause valuation" 
        by (simp add: formulaTrueIffAllClausesAreTrue)
    } hence "formulaTrue formula0 valuation" 
      by (simp add: formulaTrueIffAllClausesAreTrue)
    with ‹model valuation formula 
    have "model valuation formula0" 
      by simp
    thus ?thesis 
      by (auto simp add: satisfiable_def)
  qed
qed

lemma satisfiableAppend: 
  fixes formula1 :: Formula and formula2 :: Formula
  assumes "satisfiable (formula1 @ formula2)" 
  shows "satisfiable formula1" "satisfiable formula2"
using assms
unfolding satisfiable_def
by (auto simp add:formulaTrueAppend)

lemma modelExpand: 
  fixes formula :: Formula and literal :: Literal and valuation :: Valuation
  assumes "model valuation formula" and "var literal  vars valuation"
  shows "model (valuation @ [literal]) formula"
proof -
  from ‹model valuation formula 
  have "formulaTrue formula (valuation @ [literal])"
    by (simp add:formulaTrueAppendValuation)
  moreover
  from ‹model valuation formula 
  have "consistent valuation" 
    by simp
  with ‹var literal  vars valuation 
  have "consistent (valuation @ [literal])"
  proof (cases "inconsistent (valuation @ [literal])")
    case True
    hence "inconsistent valuation  inconsistent [literal]  ( l. literalTrue l valuation  literalFalse l [literal])"
      by (rule inconsistentAppend)
    with ‹consistent valuation 
    have " l. literalTrue l valuation  literalFalse l [literal]"
      by auto
    hence "literalFalse literal valuation" 
      by auto
    hence "var (opposite literal)  (vars valuation)"
      using valuationContainsItsLiteralsVariable [of "opposite literal" "valuation"]
      by simp
    with ‹var literal  vars valuation 
    have "False"
      by simp
    thus ?thesis ..
  qed simp
  ultimately 
  show ?thesis 
    by auto
qed



(*--------------------------------------------------------------------------------*)
subsubsection‹Tautological clauses›

lemma tautologyNotFalse:
  fixes clause :: Clause and valuation :: Valuation
  assumes "clauseTautology clause" "consistent valuation"
  shows "¬ clauseFalse clause valuation"
using assms
  clauseTautologyCharacterization[of "clause"]
  clauseFalseIffAllLiteralsAreFalse[of "clause" "valuation"]
  inconsistentCharacterization
by auto
  

lemma tautologyInTotalValuation:
assumes 
  "clauseTautology clause"
  "vars clause  vars valuation"
shows
  "clauseTrue clause valuation"
proof-
  from ‹clauseTautology clause
  obtain literal
    where "literal el clause" "opposite literal el clause"
    by (auto simp add: clauseTautologyCharacterization)
  hence "var literal  vars clause"
    using clauseContainsItsLiteralsVariable[of "literal" "clause"]
    using clauseContainsItsLiteralsVariable[of "opposite literal" "clause"]
    by simp
  hence "var literal  vars valuation"
    using ‹vars clause  vars valuation
    by auto
  hence "literalTrue literal valuation  literalFalse literal valuation"
    using varInClauseVars[of "var literal" "valuation"]
    using varInClauseVars[of "var (opposite literal)" "valuation"]
    using literalsWithSameVariableAreEqualOrOpposite
    by auto
  thus ?thesis
    using literal el clause ‹opposite literal el clause
    by (auto simp add: clauseTrueIffContainsTrueLiteral)
qed

lemma modelAppendTautology:
assumes
  "model valuation F" "clauseTautology c"
  "vars valuation  vars F  vars c"
shows
  "model valuation (F @ [c])"
using assms
using tautologyInTotalValuation[of "c" "valuation"]
by (auto simp add: formulaTrueAppend)

lemma satisfiableAppendTautology:
assumes 
  "satisfiable F" "clauseTautology c"
shows
  "satisfiable (F @ [c])"
proof-
  from ‹clauseTautology c 
  obtain l 
    where "l el c" "opposite l el c"
    by (auto simp add: clauseTautologyCharacterization)
  from ‹satisfiable F
  obtain valuation
    where "consistent valuation" "formulaTrue F valuation"
    unfolding satisfiable_def
    by auto
  show ?thesis
  proof (cases "var l  vars valuation")
    case True
    hence "literalTrue l valuation  literalFalse l valuation"
      using varInClauseVars[of "var l" "valuation"]
      by (auto simp add: literalsWithSameVariableAreEqualOrOpposite)
    hence "clauseTrue c valuation"
      using l el c ‹opposite l el c
      by (auto simp add: clauseTrueIffContainsTrueLiteral)
    thus ?thesis
      using ‹consistent valuation ‹formulaTrue F valuation
      unfolding satisfiable_def
      by (auto simp add: formulaTrueIffAllClausesAreTrue)
  next
    case False
    let ?valuation' = "valuation @ [l]"
    have "model ?valuation' F"
      using ‹var l  vars valuation
      using ‹formulaTrue F valuation ‹consistent valuation
      using modelExpand[of "valuation" "F" "l"]
      by simp
    moreover
    have "formulaTrue [c] ?valuation'"
      using l el c
      using clauseTrueIffContainsTrueLiteral[of "c" "?valuation'"]
      using formulaTrueIffAllClausesAreTrue[of "[c]" "?valuation'"]
      by auto
    ultimately
    show ?thesis
      unfolding satisfiable_def
      by (auto simp add: formulaTrueAppend)
  qed
qed

lemma modelAppendTautologicalFormula:
fixes
  F :: Formula and F' :: Formula
assumes
  "model valuation F" " c. c el F'  clauseTautology c"
  "vars valuation  vars F  vars F'"
shows
  "model valuation (F @ F')"
using assms
proof (induct F')
  case Nil
  thus ?case
    by simp
next
  case (Cons c F'')
  hence "model valuation (F @ F'')"
    by simp
  hence "model valuation ((F @ F'') @ [c])"
    using Cons(3)
    using Cons(4)
    using modelAppendTautology[of "valuation" "F @ F''" "c"]
    using varsAppendFormulae[of "F" "F''"]
    by simp
  thus ?case
    by (simp add: formulaTrueAppend)
qed


lemma satisfiableAppendTautologicalFormula:
assumes 
  "satisfiable F" " c. c el F'  clauseTautology c"
shows
  "satisfiable (F @ F')"
using assms
proof (induct F')
  case Nil
  thus ?case
    by simp
next
  case (Cons c F'')
  hence "satisfiable (F @ F'')"
    by simp
  thus ?case
    using Cons(3)
    using satisfiableAppendTautology[of "F @ F''" "c"]
    unfolding satisfiable_def
    by (simp add: formulaTrueIffAllClausesAreTrue)
qed

lemma satisfiableFilterTautologies:
shows "satisfiable F = satisfiable (filter (% c. ¬ clauseTautology c) F)"
proof (induct F)
  case Nil
  thus ?case
    by simp
next
  case (Cons c' F')
  let ?filt  = "λ F. filter (% c. ¬ clauseTautology c) F"
  let ?filt'  = "λ F. filter (% c. clauseTautology c) F"
  show ?case
  proof
    assume "satisfiable (c' # F')"
    thus "satisfiable (?filt (c' # F'))"
      unfolding satisfiable_def
      by (auto simp add: formulaTrueIffAllClausesAreTrue)
  next
    assume "satisfiable (?filt (c' # F'))"
    thus "satisfiable (c' # F')"
    proof (cases "clauseTautology c'")
      case True
      hence "?filt (c' # F') = ?filt F'"
        by auto
      hence "satisfiable (?filt F')"
        using ‹satisfiable (?filt (c' # F'))
        by simp
      hence "satisfiable F'"
        using Cons
        by simp
      thus ?thesis
        using satisfiableAppendTautology[of "F'" "c'"]
        using ‹clauseTautology c'
        unfolding satisfiable_def
        by (auto simp add: formulaTrueIffAllClausesAreTrue)
    next
      case False
      hence "?filt (c' # F') = c' # ?filt F'"
        by auto   
      hence "satisfiable (c' # ?filt F')"
        using ‹satisfiable (?filt (c' # F'))
        by simp
      moreover
      have " c. c el ?filt' F'  clauseTautology c"
        by simp
      ultimately
      have "satisfiable ((c' # ?filt F') @ ?filt' F')"
        using satisfiableAppendTautologicalFormula[of "c' # ?filt F'" "?filt' F'"]
        by (simp (no_asm_use))
      thus ?thesis
        unfolding satisfiable_def
        by (auto simp add: formulaTrueIffAllClausesAreTrue)
    qed
  qed
qed

lemma modelFilterTautologies:
assumes 
  "model valuation (filter (% c. ¬ clauseTautology c) F)" 
  "vars F  vars valuation"
shows "model valuation F"
using assms
proof (induct F)
  case Nil
  thus ?case
    by simp
next
  case (Cons c' F')
  let ?filt  = "λ F. filter (% c. ¬ clauseTautology c) F"
  let ?filt'  = "λ F. filter (% c. clauseTautology c) F"
  show ?case
  proof (cases "clauseTautology c'")
    case True
    thus ?thesis
      using Cons
      using tautologyInTotalValuation[of "c'" "valuation"]
      by auto
  next
    case False
    hence "?filt (c' # F') = c' # ?filt F'"
      by auto   
    hence "model valuation (c' # ?filt F')"
      using ‹model valuation (?filt (c' # F'))
      by simp
    moreover
    have " c. c el ?filt' F'  clauseTautology c"
      by simp
    moreover 
    have "vars ((c' # ?filt F') @ ?filt' F')  vars valuation"
      using varsSubsetFormula[of "?filt F'" "F'"]
      using varsSubsetFormula[of "?filt' F'" "F'"]
      using varsAppendFormulae[of "c' # ?filt F'" "?filt' F'"]
      using Cons(3)
      using formulaContainsItsClausesVariables[of _ "?filt F'"]
      by auto
    ultimately
    have "model valuation ((c' # ?filt F') @ ?filt' F')"
      using modelAppendTautologicalFormula[of "valuation" "c' # ?filt F'" "?filt' F'"]
      using varsAppendFormulae[of "c' # ?filt F'" "?filt' F'"]
      by (simp (no_asm_use)) (blast)
    thus ?thesis
      using formulaTrueAppend[of "?filt F'" "?filt' F'" "valuation"]
      using formulaTrueIffAllClausesAreTrue[of "?filt F'" "valuation"]
      using formulaTrueIffAllClausesAreTrue[of "?filt' F'" "valuation"]
      using formulaTrueIffAllClausesAreTrue[of "F'" "valuation"]      
      by auto
  qed
qed

(*------------------------------------------------------------------*)
subsubsection‹Entailment›

text‹Formula entails literal if it is true in all its models›
definition formulaEntailsLiteral :: "Formula  Literal  bool"
where
"formulaEntailsLiteral formula literal == 
   (valuation::Valuation). model valuation formula  literalTrue literal valuation"

text‹Clause implies literal if it is true in all its models›
definition clauseEntailsLiteral  :: "Clause  Literal  bool"
where
"clauseEntailsLiteral clause literal == 
   (valuation::Valuation). model valuation clause  literalTrue literal valuation"

text‹Formula entails clause if it is true in all its models›
definition formulaEntailsClause  :: "Formula  Clause  bool"
where
"formulaEntailsClause formula clause == 
   (valuation::Valuation). model valuation formula  model valuation clause"

text‹Formula entails valuation if it entails its every literal›
definition formulaEntailsValuation :: "Formula  Valuation  bool"
where
"formulaEntailsValuation formula valuation ==
     literal. literal el valuation  formulaEntailsLiteral formula literal"

text‹Formula entails formula if it is true in all its models›
definition formulaEntailsFormula  :: "Formula  Formula  bool"
where
formulaEntailsFormula_def: "formulaEntailsFormula formula formula' == 
   (valuation::Valuation). model valuation formula  model valuation formula'"

lemma singleLiteralClausesEntailItsLiteral: 
  fixes clause :: Clause and literal :: Literal
  assumes "length clause = 1" and "literal el clause"
  shows "clauseEntailsLiteral clause literal"
proof -
  from assms 
  have onlyLiteral: " l. l el clause  l = literal" 
    using lengthOneImpliesOnlyElement[of "clause" "literal"]
    by simp
  {
    fix valuation :: Valuation
    assume "clauseTrue clause valuation"
    with onlyLiteral  
    have "literalTrue literal valuation" 
      by (auto simp add:clauseTrueIffContainsTrueLiteral)
  }
  thus ?thesis 
    by (simp add:clauseEntailsLiteral_def)
qed

lemma clauseEntailsLiteralThenFormulaEntailsLiteral:
  fixes clause :: Clause and formula :: Formula and literal :: Literal
  assumes "clause el formula" and "clauseEntailsLiteral clause literal"
  shows "formulaEntailsLiteral formula literal"
proof -
  {
    fix valuation :: Valuation
    assume modelFormula: "model valuation formula"

    with clause el formula 
    have "clauseTrue clause valuation"
      by (simp add:formulaTrueIffAllClausesAreTrue)
    with modelFormula ‹clauseEntailsLiteral clause literal 
    have "literalTrue literal valuation"
      by (auto simp add: clauseEntailsLiteral_def)
  }
  thus ?thesis 
    by (simp add:formulaEntailsLiteral_def)
qed

lemma formulaEntailsLiteralAppend: 
  fixes formula :: Formula and formula' :: Formula and literal :: Literal
  assumes "formulaEntailsLiteral formula literal"
  shows  "formulaEntailsLiteral (formula @ formula') literal"
proof -
  {
    fix valuation :: Valuation
    assume modelFF': "model valuation (formula @ formula')"

    hence "formulaTrue formula valuation" 
      by (simp add: formulaTrueAppend)
    with modelFF' and ‹formulaEntailsLiteral formula literal 
    have "literalTrue literal valuation" 
      by (simp add: formulaEntailsLiteral_def)
  }
  thus ?thesis 
    by (simp add: formulaEntailsLiteral_def)
qed

lemma formulaEntailsLiteralSubset: 
  fixes formula :: Formula and formula' :: Formula and literal :: Literal
  assumes "formulaEntailsLiteral formula literal" and " (c::Clause) . c el formula  c el formula'"
  shows "formulaEntailsLiteral formula' literal"
proof -
  {
    fix valuation :: Valuation
    assume modelF': "model valuation formula'"
    with  (c::Clause) . c el formula  c el formula' 
    have "formulaTrue formula valuation"
      by (auto simp add: formulaTrueIffAllClausesAreTrue)
    with modelF' ‹formulaEntailsLiteral formula literal 
    have "literalTrue literal valuation"
      by (simp add: formulaEntailsLiteral_def)
  }
  thus ?thesis 
    by (simp add:formulaEntailsLiteral_def)
qed


lemma formulaEntailsLiteralRemoveAll:
  fixes formula :: Formula and clause :: Clause and literal :: Literal
  assumes "formulaEntailsLiteral (removeAll clause formula) literal"
  shows "formulaEntailsLiteral formula literal"
proof -
  {
    fix valuation :: Valuation
    assume modelF: "model valuation formula"
    hence "formulaTrue (removeAll clause formula) valuation" 
      by (auto simp add:formulaTrueRemoveAll)
    with modelF ‹formulaEntailsLiteral (removeAll clause formula) literal 
    have "literalTrue literal valuation"
      by (auto simp add:formulaEntailsLiteral_def)
  }
  thus ?thesis 
    by (simp add:formulaEntailsLiteral_def)
qed

lemma formulaEntailsLiteralRemoveAllAppend:
  fixes formula1 :: Formula and formula2 :: Formula and clause :: Clause and valuation :: Valuation
  assumes "formulaEntailsLiteral ((removeAll clause formula1) @ formula2) literal" 
  shows "formulaEntailsLiteral (formula1 @ formula2) literal"
proof -
  {
    fix valuation :: Valuation
    assume modelF: "model valuation (formula1 @ formula2)"
    hence "formulaTrue ((removeAll clause formula1) @ formula2) valuation" 
      by (auto simp add:formulaTrueRemoveAll formulaTrueAppend)
    with modelF ‹formulaEntailsLiteral ((removeAll clause formula1) @ formula2) literal 
    have "literalTrue literal valuation"
      by (auto simp add:formulaEntailsLiteral_def)
  }
  thus ?thesis 
    by (simp add:formulaEntailsLiteral_def)
qed

lemma formulaEntailsItsClauses: 
  fixes clause :: Clause and formula :: Formula
  assumes "clause el formula"
  shows "formulaEntailsClause formula clause"
using assms
by (simp add: formulaEntailsClause_def formulaTrueIffAllClausesAreTrue)

lemma formulaEntailsClauseAppend: 
  fixes clause :: Clause and formula :: Formula and formula' :: Formula
  assumes "formulaEntailsClause formula clause"
  shows "formulaEntailsClause (formula @ formula') clause"
proof -
  { 
    fix valuation :: Valuation
    assume "model valuation (formula @ formula')"
    hence "model valuation formula"
      by (simp add:formulaTrueAppend)
    with ‹formulaEntailsClause formula clause 
    have "clauseTrue clause valuation"
      by (simp add:formulaEntailsClause_def)
  }
  thus ?thesis 
    by (simp add: formulaEntailsClause_def)
qed

lemma formulaUnsatIffImpliesEmptyClause: 
  fixes formula :: Formula
  shows "formulaEntailsClause formula [] = (¬ satisfiable formula)"
by (auto simp add: formulaEntailsClause_def satisfiable_def)

lemma formulaTrueExtendWithEntailedClauses:
  fixes formula :: Formula and formula0 :: Formula and valuation :: Valuation
  assumes formulaEntailed: " (clause::Clause). clause el formula  formulaEntailsClause formula0 clause" and "consistent valuation"
  shows "formulaTrue formula0 valuation  formulaTrue formula valuation"
proof
  assume "formulaTrue formula0 valuation"
  {
    fix clause :: Clause
    assume "clause el formula"
    with formulaEntailed 
    have "formulaEntailsClause formula0 clause"
      by simp
    with ‹formulaTrue formula0 valuation ‹consistent valuation 
    have "clauseTrue clause valuation"
      by (simp add:formulaEntailsClause_def)
  }
  thus "formulaTrue formula valuation"
    by (simp add:formulaTrueIffAllClausesAreTrue)
qed


lemma formulaEntailsFormulaIffEntailsAllItsClauses: 
  fixes formula :: Formula and formula' :: Formula
  shows "formulaEntailsFormula formula formula' = ( clause::Clause. clause el formula'  formulaEntailsClause formula clause)"
     (is "?lhs = ?rhs")
proof
  assume ?lhs
  show ?rhs
  proof
    fix clause :: Clause
    show "clause el formula'  formulaEntailsClause formula clause"
    proof
      assume "clause el formula'"
      show "formulaEntailsClause formula clause"
      proof -
        {
          fix valuation :: Valuation
          assume "model valuation formula"
          with ?lhs 
          have "model valuation formula'"
            by (simp add:formulaEntailsFormula_def)
          with clause el formula' 
          have "clauseTrue clause valuation"
            by (simp add:formulaTrueIffAllClausesAreTrue)
        }
        thus ?thesis 
          by (simp add:formulaEntailsClause_def)
      qed
    qed
  qed
next
  assume ?rhs
  thus ?lhs
  proof -
    {
      fix valuation :: Valuation
      assume "model valuation formula"
      {
        fix clause :: Clause
        assume "clause el formula'"
        with ?rhs 
        have "formulaEntailsClause formula clause"
          by auto
        with ‹model valuation formula 
        have "clauseTrue clause valuation"
          by (simp add:formulaEntailsClause_def)
      }
      hence "(formulaTrue formula' valuation)"
        by (simp add:formulaTrueIffAllClausesAreTrue)
    }
    thus ?thesis
      by (simp add:formulaEntailsFormula_def)
  qed
qed

lemma formulaEntailsFormulaThatEntailsClause: 
  fixes formula1 :: Formula and formula2 :: Formula and clause :: Clause
  assumes "formulaEntailsFormula formula1 formula2" and "formulaEntailsClause formula2 clause"
  shows "formulaEntailsClause formula1 clause"
using assms
by (simp add: formulaEntailsClause_def formulaEntailsFormula_def)


lemma 
  fixes formula1 :: Formula and formula2 :: Formula and formula1' :: Formula and literal :: Literal
  assumes "formulaEntailsLiteral (formula1 @ formula2) literal" and "formulaEntailsFormula formula1' formula1"
  shows "formulaEntailsLiteral (formula1' @ formula2) literal"
proof -
  {
    fix valuation :: Valuation
    assume "model valuation (formula1' @ formula2)"
    hence "consistent valuation" and "formulaTrue formula1' valuation"  "formulaTrue formula2 valuation"
      by (auto simp add: formulaTrueAppend)
    with ‹formulaEntailsFormula formula1' formula1 
    have "model valuation formula1"
      by (simp add:formulaEntailsFormula_def)
    with ‹formulaTrue formula2 valuation 
    have "model valuation (formula1 @ formula2)"
      by (simp add: formulaTrueAppend)
    with ‹formulaEntailsLiteral (formula1 @ formula2) literal 
    have "literalTrue literal valuation"
      by (simp add:formulaEntailsLiteral_def)
  }
  thus ?thesis
    by (simp add:formulaEntailsLiteral_def)
qed


lemma formulaFalseInEntailedValuationIsUnsatisfiable: 
  fixes formula :: Formula and valuation :: Valuation
  assumes "formulaFalse formula valuation" and 
          "formulaEntailsValuation formula valuation"
  shows "¬ satisfiable formula"
proof -
  from ‹formulaFalse formula valuation obtain clause :: Clause
    where "clause el formula" and "clauseFalse clause valuation"
    by (auto simp add:formulaFalseIffContainsFalseClause)
  {
    fix valuation' :: Valuation
    assume modelV': "model valuation' formula"
    with clause el formula obtain literal :: Literal 
      where "literal el clause" and "literalTrue literal valuation'"
      by (auto simp add: formulaTrueIffAllClausesAreTrue clauseTrueIffContainsTrueLiteral)
    with ‹clauseFalse clause valuation 
    have "literalFalse literal valuation"
      by (auto simp add:clauseFalseIffAllLiteralsAreFalse)
    with ‹formulaEntailsValuation formula valuation 
    have "formulaEntailsLiteral formula (opposite literal)"
      unfolding formulaEntailsValuation_def
      by simp
    with modelV' 
    have "literalFalse literal valuation'"
      by (auto simp add:formulaEntailsLiteral_def)
    from ‹literalTrue literal valuation' ‹literalFalse literal valuation' modelV' 
    have "False"
      by (simp add:inconsistentCharacterization)
  }
  thus ?thesis
    by (auto simp add:satisfiable_def)
qed

lemma formulaFalseInEntailedOrPureValuationIsUnsatisfiable: 
  fixes formula :: Formula and valuation :: Valuation
  assumes "formulaFalse formula valuation" and 
  " literal'. literal' el valuation  formulaEntailsLiteral formula literal'   ¬ opposite literal' el formula"
  shows "¬ satisfiable formula"
proof -
  from ‹formulaFalse formula valuation obtain clause :: Clause
    where "clause el formula" and "clauseFalse clause valuation"
    by (auto simp add:formulaFalseIffContainsFalseClause)
  {
    fix valuation' :: Valuation
    assume modelV': "model valuation' formula"
    with clause el formula obtain literal :: Literal 
      where "literal el clause" and "literalTrue literal valuation'"
      by (auto simp add: formulaTrueIffAllClausesAreTrue clauseTrueIffContainsTrueLiteral)
    with ‹clauseFalse clause valuation 
    have "literalFalse literal valuation"
      by (auto simp add:clauseFalseIffAllLiteralsAreFalse)
    with  literal'. literal' el valuation  formulaEntailsLiteral formula literal'   ¬ opposite literal' el formula 
    have "formulaEntailsLiteral formula (opposite literal)  ¬ literal el formula"
      by auto
    moreover
    {
      assume "formulaEntailsLiteral formula (opposite literal)"
      with modelV' 
      have "literalFalse literal valuation'"
        by (auto simp add:formulaEntailsLiteral_def)
      from ‹literalTrue literal valuation' ‹literalFalse literal valuation' modelV' 
      have "False"
        by (simp add:inconsistentCharacterization)
    }
    moreover
    {
      assume "¬ literal el formula"
      with clause el formula literal el clause
      have "False"
        by (simp add:literalElFormulaCharacterization)
    }
    ultimately
    have "False"
      by auto
  }
  thus ?thesis
    by (auto simp add:satisfiable_def)
qed


lemma unsatisfiableFormulaWithSingleLiteralClause:
  fixes formula :: Formula and literal :: Literal
  assumes "¬ satisfiable formula" and "[literal] el formula"
  shows "formulaEntailsLiteral (removeAll [literal] formula) (opposite literal)"
proof -
  {
    fix valuation :: Valuation
    assume "model valuation (removeAll [literal] formula)"
    hence "literalFalse literal valuation"
    proof (cases "var literal  vars valuation")
      case True
      {
        assume "literalTrue literal valuation"
        with ‹model valuation (removeAll [literal] formula) 
        have "model valuation formula"
          by (auto simp add:formulaTrueIffAllClausesAreTrue)
        with ¬ satisfiable formula 
        have "False"
          by (auto simp add:satisfiable_def)
      }
      with True 
      show ?thesis 
        using variableDefinedImpliesLiteralDefined [of "literal" "valuation"]
        by auto
    next
      case False
      with ‹model valuation (removeAll [literal] formula) 
      have "model (valuation @ [literal]) (removeAll [literal] formula)"
        by (rule modelExpand)
      hence 
        "formulaTrue (removeAll [literal] formula) (valuation @ [literal])" and "consistent (valuation @ [literal])"
        by auto
      from ‹formulaTrue (removeAll [literal] formula) (valuation @ [literal]) 
      have "formulaTrue formula (valuation @ [literal])"
        by (rule trueFormulaWithSingleLiteralClause)
      with ‹consistent (valuation @ [literal]) 
      have "model (valuation @ [literal]) formula"
        by simp
      with ¬ satisfiable formula 
      have "False"
        by (auto simp add:satisfiable_def)
      thus ?thesis ..
    qed
  }
  thus ?thesis 
    by (simp add:formulaEntailsLiteral_def)
qed

lemma unsatisfiableFormulaWithSingleLiteralClauses:
  fixes F::Formula and c::Clause
  assumes "¬ satisfiable (F @ val2form (oppositeLiteralList c))" "¬ clauseTautology c"
  shows "formulaEntailsClause F c"
proof-
  {
    fix v::Valuation
    assume "model v F"
    with ¬ satisfiable (F @ val2form (oppositeLiteralList c))
    have "¬ formulaTrue (val2form (oppositeLiteralList c)) v"
      unfolding satisfiable_def
      by (auto simp add: formulaTrueAppend)
    have "clauseTrue c v"
    proof (cases " l. l el c  (literalTrue l v)")
      case True
      thus ?thesis
        using clauseTrueIffContainsTrueLiteral
        by simp
    next
      case False
      let ?v' = "v @ (oppositeLiteralList c)"

      have "¬ inconsistent (oppositeLiteralList c)"
      proof-
        {
          assume "¬ ?thesis"
          then obtain l::Literal
            where "l el (oppositeLiteralList c)" "opposite l el (oppositeLiteralList c)"
            using inconsistentCharacterization [of "oppositeLiteralList c"]
            by auto
          hence "(opposite l) el c" "l el c"
            using literalElListIffOppositeLiteralElOppositeLiteralList[of "l" "c"]
            using literalElListIffOppositeLiteralElOppositeLiteralList[of "opposite l" "c"]
            by auto
          hence "clauseTautology c"
            using clauseTautologyCharacterization[of "c"]
            by auto
          with ¬ clauseTautology c
          have "False"
            by simp
        }
        thus ?thesis
          by auto
      qed
      with False ‹model v F
      have "consistent ?v'"
        using inconsistentAppend[of "v" "oppositeLiteralList c"]
        unfolding consistent_def
        using literalElListIffOppositeLiteralElOppositeLiteralList
        by auto
      moreover
      from ‹model v F
      have "formulaTrue F ?v'"
        using formulaTrueAppendValuation
        by simp
      moreover
      have "formulaTrue (val2form (oppositeLiteralList c)) ?v'"
        using val2formFormulaTrue[of "oppositeLiteralList c" "v @ oppositeLiteralList c"]
        by simp
      ultimately
      have "model ?v' (F @ val2form (oppositeLiteralList c))"
        by (simp add: formulaTrueAppend)
      with ¬ satisfiable (F @ val2form (oppositeLiteralList c))
      have "False"
        unfolding satisfiable_def
        by auto
      thus ?thesis
        by simp
    qed
  }
  thus ?thesis
    unfolding formulaEntailsClause_def
    by simp
qed

lemma satisfiableEntailedFormula:
  fixes formula0 :: Formula and formula :: Formula
  assumes "formulaEntailsFormula formula0 formula"
  shows "satisfiable formula0  satisfiable formula"
proof
  assume "satisfiable formula0"
  show "satisfiable formula"
  proof -
    from ‹satisfiable formula0 obtain valuation :: Valuation
      where "model valuation formula0" 
      by (auto simp add: satisfiable_def)
    with ‹formulaEntailsFormula formula0 formula 
    have "model valuation formula" 
      by (simp add: formulaEntailsFormula_def)
    thus ?thesis 
      by (auto simp add: satisfiable_def)
  qed
qed

lemma val2formIsEntailed:
shows "formulaEntailsValuation (F' @ val2form valuation @ F'') valuation"
proof-
  {
    fix l::Literal
    assume "l el valuation"
    hence "[l] el val2form valuation"
      by (induct valuation) (auto)

    have "formulaEntailsLiteral (F' @ val2form valuation @ F'') l"
    proof-
      {
        fix valuation'::Valuation
        assume "formulaTrue (F' @ val2form valuation @ F'') valuation'"
        hence "literalTrue l valuation'"
          using [l] el val2form valuation
          using formulaTrueIffAllClausesAreTrue[of "F' @ val2form valuation @ F''" "valuation'"]
          by (auto simp add: clauseTrueIffContainsTrueLiteral)
      } thus ?thesis
        unfolding formulaEntailsLiteral_def
        by simp
    qed
  }
  thus ?thesis
    unfolding formulaEntailsValuation_def
    by simp
qed


(*------------------------------------------------------------------*)
subsubsection‹Equivalency›

text‹Formulas are equivalent if they have same models.›
definition equivalentFormulae :: "Formula  Formula  bool"
where
"equivalentFormulae formula1 formula2 ==
   (valuation::Valuation). model valuation formula1 = model valuation formula2"

lemma equivalentFormulaeIffEntailEachOther:
  fixes formula1 :: Formula and formula2 :: Formula
  shows "equivalentFormulae formula1 formula2 = (formulaEntailsFormula formula1 formula2  formulaEntailsFormula formula2 formula1)"
by (auto simp add:formulaEntailsFormula_def equivalentFormulae_def)

lemma equivalentFormulaeReflexivity: 
  fixes formula :: Formula
  shows "equivalentFormulae formula formula"
unfolding equivalentFormulae_def
by auto

lemma equivalentFormulaeSymmetry: 
  fixes formula1 :: Formula and formula2 :: Formula
  shows "equivalentFormulae formula1 formula2 = equivalentFormulae formula2 formula1"
unfolding equivalentFormulae_def
by auto

lemma equivalentFormulaeTransitivity: 
  fixes formula1 :: Formula and formula2 :: Formula and formula3 :: Formula
  assumes "equivalentFormulae formula1 formula2" and "equivalentFormulae formula2 formula3"
  shows "equivalentFormulae formula1 formula3"
using assms
unfolding equivalentFormulae_def
by auto

lemma equivalentFormulaeAppend: 
  fixes formula1 :: Formula and formula1' :: Formula and formula2 :: Formula
  assumes "equivalentFormulae formula1 formula1'"
  shows "equivalentFormulae (formula1 @ formula2) (formula1' @ formula2)"
using assms
unfolding equivalentFormulae_def
by (auto simp add: formulaTrueAppend)

lemma satisfiableEquivalent: 
  fixes formula1 :: Formula and formula2 :: Formula
  assumes "equivalentFormulae formula1 formula2"
  shows "satisfiable formula1 = satisfiable formula2"
using assms
unfolding equivalentFormulae_def
unfolding satisfiable_def
by auto

lemma satisfiableEquivalentAppend: 
  fixes formula1 :: Formula and formula1' :: Formula and formula2 :: Formula
  assumes "equivalentFormulae formula1 formula1'" and "satisfiable (formula1 @ formula2)"
  shows "satisfiable (formula1' @ formula2)"
using assms
proof -
  from ‹satisfiable (formula1 @ formula2) obtain valuation::Valuation
    where "consistent valuation" "formulaTrue formula1 valuation" "formulaTrue formula2 valuation"
    unfolding satisfiable_def
    by (auto simp add: formulaTrueAppend)
  from ‹equivalentFormulae formula1 formula1' ‹consistent valuation ‹formulaTrue formula1 valuation 
  have "formulaTrue formula1' valuation"
    unfolding equivalentFormulae_def
    by auto
  show ?thesis
    using ‹consistent valuation ‹formulaTrue formula1' valuation ‹formulaTrue formula2 valuation
    unfolding satisfiable_def
    by (auto simp add: formulaTrueAppend)
qed


lemma replaceEquivalentByEquivalent:
  fixes formula :: Formula and formula' :: Formula and formula1 :: Formula and formula2 :: Formula
  assumes "equivalentFormulae formula formula'" 
  shows "equivalentFormulae (formula1 @ formula @ formula2) (formula1 @ formula' @ formula2)"
unfolding equivalentFormulae_def
proof
  fix v :: Valuation
  show "model v (formula1 @ formula @ formula2) = model v (formula1 @ formula' @ formula2)"
  proof
    assume "model v (formula1 @ formula @ formula2)"
    hence *: "consistent v" "formulaTrue formula1 v" "formulaTrue formula v" "formulaTrue formula2 v"
      by (auto simp add: formulaTrueAppend)
    from ‹consistent v ‹formulaTrue formula v ‹equivalentFormulae formula formula'
    have "formulaTrue formula' v"
      unfolding equivalentFormulae_def
      by auto
    thus "model v (formula1 @ formula' @ formula2)"
      using *
      by (simp add: formulaTrueAppend)
  next
    assume "model v (formula1 @ formula' @ formula2)"
    hence *: "consistent v" "formulaTrue formula1 v" "formulaTrue formula' v" "formulaTrue formula2 v"
      by (auto simp add: formulaTrueAppend)
    from ‹consistent v ‹formulaTrue formula' v ‹equivalentFormulae formula formula'
    have "formulaTrue formula v"
      unfolding equivalentFormulae_def
      by auto
    thus "model v (formula1 @ formula @ formula2)"
      using *
      by (simp add: formulaTrueAppend)
  qed
qed

lemma clauseOrderIrrelevant:
  shows "equivalentFormulae (F1 @ F @ F' @ F2) (F1 @ F' @ F @ F2)"
unfolding equivalentFormulae_def
by (auto simp add: formulaTrueIffAllClausesAreTrue)

lemma extendEquivalentFormulaWithEntailedClause:
  fixes formula1 :: Formula and formula2 :: Formula and clause :: Clause
  assumes "equivalentFormulae formula1 formula2" and "formulaEntailsClause formula2 clause"
  shows "equivalentFormulae formula1 (formula2 @ [clause])"
  unfolding equivalentFormulae_def
proof
  fix valuation :: Valuation
  show "model valuation formula1 = model valuation (formula2 @ [clause])"
  proof
    assume "model valuation formula1"
    hence "consistent valuation"
      by simp
    from ‹model valuation formula1 ‹equivalentFormulae formula1 formula2
    have "model valuation formula2"
      unfolding equivalentFormulae_def
      by simp
    moreover
    from ‹model valuation formula2 ‹formulaEntailsClause formula2 clause
    have "clauseTrue clause valuation"
      unfolding formulaEntailsClause_def
      by simp
    ultimately show
      "model valuation (formula2 @ [clause])"
      by (simp add: formulaTrueAppend)
  next
    assume "model valuation (formula2 @ [clause])"
    hence "consistent valuation"
      by simp
    from ‹model valuation (formula2 @ [clause])
    have "model valuation formula2"
      by (simp add:formulaTrueAppend)
    with ‹equivalentFormulae formula1 formula2
    show "model valuation formula1"
      unfolding equivalentFormulae_def
      by auto
  qed
qed

lemma entailsLiteralRelpacePartWithEquivalent:
  assumes "equivalentFormulae F F'" and "formulaEntailsLiteral (F1 @ F @ F2) l"
  shows "formulaEntailsLiteral (F1 @ F' @ F2) l"
proof-
  {
    fix v::Valuation
    assume "model v (F1 @ F' @ F2)"
    hence "consistent v" and "formulaTrue F1 v" and "formulaTrue F' v" and "formulaTrue F2 v"
      by (auto simp add:formulaTrueAppend)
    with ‹equivalentFormulae F F'
    have "formulaTrue F v"
      unfolding equivalentFormulae_def
      by auto
    with ‹consistent v ‹formulaTrue F1 v ‹formulaTrue F2 v
    have "model v (F1 @ F @ F2)"
      by (auto simp add:formulaTrueAppend)
    with ‹formulaEntailsLiteral (F1 @ F @ F2) l
    have "literalTrue l v"
      unfolding formulaEntailsLiteral_def
      by auto
  }
  thus ?thesis
    unfolding formulaEntailsLiteral_def
    by auto
qed



(*--------------------------------------------------------------------------------*)
subsubsection‹Remove false and duplicate literals of a clause›

definition
removeFalseLiterals :: "Clause  Valuation  Clause"
where
"removeFalseLiterals clause valuation = filter (λ l. ¬ literalFalse l valuation) clause"

lemma clauseTrueRemoveFalseLiterals:
  assumes "consistent v"
  shows "clauseTrue c v = clauseTrue (removeFalseLiterals c v) v"
using assms
unfolding removeFalseLiterals_def
by (auto simp add: clauseTrueIffContainsTrueLiteral inconsistentCharacterization)

lemma clauseTrueRemoveDuplicateLiterals:
  shows "clauseTrue c v = clauseTrue (remdups c) v"
by (induct c) (auto simp add: clauseTrueIffContainsTrueLiteral)

lemma removeDuplicateLiteralsEquivalentClause:
  shows "equivalentFormulae [remdups clause] [clause]"
unfolding equivalentFormulae_def
by (auto simp add: formulaTrueIffAllClausesAreTrue clauseTrueIffContainsTrueLiteral)

lemma falseLiteralsCanBeRemoved:
(* val2form v - some single literal clauses *)
fixes F::Formula and F'::Formula and v::Valuation
assumes "equivalentFormulae (F1 @ val2form v @ F2) F'"
shows "equivalentFormulae (F1 @ val2form v @ [removeFalseLiterals c v] @ F2) (F' @ [c])" 
            (is "equivalentFormulae ?lhs ?rhs")
unfolding equivalentFormulae_def
proof
  fix v' :: Valuation
  show "model v' ?lhs = model v' ?rhs"
  proof
    assume "model v' ?lhs"
    hence "consistent v'" and  
      "formulaTrue (F1 @ val2form v @ F2) v'" and 
      "clauseTrue (removeFalseLiterals c v) v'"
      by (auto simp add: formulaTrueAppend formulaTrueIffAllClausesAreTrue)

    from ‹consistent v' ‹formulaTrue (F1 @ val2form v @ F2) v' ‹equivalentFormulae (F1 @ val2form v @ F2) F'
    have "model v' F'"
      unfolding equivalentFormulae_def
      by auto
    moreover
    from ‹clauseTrue (removeFalseLiterals c v) v'
    have "clauseTrue c v'"
      unfolding removeFalseLiterals_def
      by (auto simp add: clauseTrueIffContainsTrueLiteral)
    ultimately
    show "model v' ?rhs"
      by (simp add: formulaTrueAppend)
  next
    assume "model v' ?rhs"
    hence "consistent v'" and "formulaTrue F' v'" and "clauseTrue c v'"
      by (auto simp add: formulaTrueAppend formulaTrueIffAllClausesAreTrue)

    from ‹consistent v' ‹formulaTrue F' v' ‹equivalentFormulae (F1 @ val2form v @ F2) F'
    have "model v' (F1 @ val2form v @ F2)"
      unfolding equivalentFormulae_def
      by auto
    moreover
    have "clauseTrue (removeFalseLiterals c v) v'"
    proof-
      from ‹clauseTrue c v' 
      obtain l :: Literal
        where "l el c" and "literalTrue l v'"
        by (auto simp add: clauseTrueIffContainsTrueLiteral)
      have "¬ literalFalse l v"
      proof-
        {
          assume "¬ ?thesis"
          hence "opposite l el v"
            by simp
          with ‹model v' (F1 @ val2form v @ F2)
          have "opposite l el v'"
            using val2formFormulaTrue[of "v" "v'"]
            by auto (simp add: formulaTrueAppend)
          with ‹literalTrue l v' ‹consistent v'
          have "False"
            by (simp add: inconsistentCharacterization)
        }
        thus ?thesis
          by auto
      qed
      with l el c
      have  "l el (removeFalseLiterals c v)"
        unfolding removeFalseLiterals_def
        by simp
      with ‹literalTrue l v'
      show ?thesis
        by (auto simp add: clauseTrueIffContainsTrueLiteral)
    qed
    ultimately
    show "model v' ?lhs"
      by (simp add: formulaTrueAppend)
  qed
qed

lemma falseAndDuplicateLiteralsCanBeRemoved:
(* val2form v - some single literal clauses *)
assumes "equivalentFormulae (F1 @ val2form v @ F2) F'"
shows "equivalentFormulae (F1 @ val2form v @ [remdups (removeFalseLiterals c v)] @ F2) (F' @ [c])" 
  (is "equivalentFormulae ?lhs ?rhs")
proof-
  from ‹equivalentFormulae (F1 @ val2form v @ F2) F' 
  have "equivalentFormulae (F1 @ val2form v @ [removeFalseLiterals c v] @ F2) (F' @ [c])"
    using falseLiteralsCanBeRemoved
    by simp
  have "equivalentFormulae [remdups (removeFalseLiterals c v)] [removeFalseLiterals c v]"
    using removeDuplicateLiteralsEquivalentClause
    by simp
  hence "equivalentFormulae (F1 @ val2form v @ [remdups (removeFalseLiterals c v)] @ F2)
    (F1 @ val2form v @ [removeFalseLiterals c v] @ F2)"
    using replaceEquivalentByEquivalent
    [of "[remdups (removeFalseLiterals c v)]" "[removeFalseLiterals c v]" "F1 @ val2form v" "F2"]
    by auto
  thus ?thesis
    using ‹equivalentFormulae (F1 @ val2form v @ [removeFalseLiterals c v] @ F2) (F' @ [c])
    using equivalentFormulaeTransitivity[of 
              "(F1 @ val2form v @ [remdups (removeFalseLiterals c v)] @ F2)"
              "(F1 @ val2form v @ [removeFalseLiterals c v] @ F2)" 
              "F' @ [c]"]
    by simp
qed

lemma satisfiedClauseCanBeRemoved:
assumes
  "equivalentFormulae (F @ val2form v) F'"
  "clauseTrue c v"
shows "equivalentFormulae (F @ val2form v) (F' @ [c])"
unfolding equivalentFormulae_def
proof
  fix v' :: Valuation
  show "model v' (F @ val2form v) = model v' (F' @ [c])"
  proof
    assume "model v' (F @ val2form v)"
    hence "consistent v'" and "formulaTrue (F @ val2form v) v'"
      by auto
    
    from ‹model v' (F @ val2form v) ‹equivalentFormulae (F @ val2form v) F'
    have "model v' F'"
      unfolding equivalentFormulae_def
      by auto
    moreover
    have "clauseTrue c v'"
    proof-
      from ‹clauseTrue c v
      obtain l :: Literal
        where "literalTrue l v" and "l el c"
        by (auto simp add:clauseTrueIffContainsTrueLiteral)
      with ‹formulaTrue (F @ val2form v) v'
      have "literalTrue l v'"
        using val2formFormulaTrue[of "v" "v'"]
        using formulaTrueAppend[of "F" "val2form v"]
        by simp
      thus ?thesis
        using l el c
        by (auto simp add:clauseTrueIffContainsTrueLiteral)
    qed
    ultimately
    show "model v' (F' @ [c])"
      by (simp add: formulaTrueAppend)
  next
    assume "model v' (F' @ [c])"
    thus "model v' (F @ val2form v)"
      using ‹equivalentFormulae (F @ val2form v) F'
      unfolding equivalentFormulae_def
      using formulaTrueAppend[of "F'" "[c]" "v'"]
      by auto
  qed
qed

lemma formulaEntailsClauseRemoveEntailedLiteralOpposites:
assumes
  "formulaEntailsClause F clause"
  "formulaEntailsValuation F valuation"
shows
  "formulaEntailsClause F (list_diff clause (oppositeLiteralList valuation))"
proof-
  {
    fix valuation'
    assume "model valuation' F"
    hence "consistent valuation'" "formulaTrue F valuation'"
      by (auto simp add: formulaTrueAppend)

    have "model valuation' clause"
      using ‹consistent valuation'
      using ‹formulaTrue F valuation'
      using ‹formulaEntailsClause F clause
      unfolding formulaEntailsClause_def
      by simp

    then obtain l::Literal
      where "l el clause" "literalTrue l valuation'"
      by (auto simp add: clauseTrueIffContainsTrueLiteral)
    moreover
    hence "¬ l el (oppositeLiteralList valuation)"
    proof-
      {
        assume "l el (oppositeLiteralList valuation)"
        hence "(opposite l) el valuation"
          using literalElListIffOppositeLiteralElOppositeLiteralList[of "l" "oppositeLiteralList valuation"]
          by simp
        hence "formulaEntailsLiteral F (opposite l)"
          using ‹formulaEntailsValuation F valuation
          unfolding formulaEntailsValuation_def
          by simp
        hence "literalFalse l valuation'"
          using ‹consistent valuation'
          using ‹formulaTrue F valuation'
          unfolding formulaEntailsLiteral_def
          by simp
        with ‹literalTrue l valuation'
          ‹consistent valuation'
        have False
          by (simp add: inconsistentCharacterization)
      } thus ?thesis
        by auto
    qed
    ultimately
    have "model valuation' (list_diff clause (oppositeLiteralList valuation))"
      using ‹consistent valuation'
      using listDiffIff[of "l" "clause" "oppositeLiteralList valuation"]
      by (auto simp add: clauseTrueIffContainsTrueLiteral)
  } thus ?thesis
    unfolding formulaEntailsClause_def
    by simp
qed



(*--------------------------------------------------------------------------------*)
subsubsection‹Resolution›

definition
"resolve clause1 clause2 literal == removeAll literal clause1 @ removeAll (opposite literal) clause2"

lemma resolventIsEntailed: 
  fixes clause1 :: Clause and clause2 :: Clause and literal :: Literal
  shows "formulaEntailsClause [clause1, clause2] (resolve clause1 clause2 literal)"
proof -
  {
    fix valuation :: Valuation
    assume "model valuation [clause1, clause2]"
    from ‹model valuation [clause1, clause2] obtain l1 :: Literal
      where "l1 el clause1" and "literalTrue l1 valuation"
      by (auto simp add: formulaTrueIffAllClausesAreTrue clauseTrueIffContainsTrueLiteral)
    from ‹model valuation [clause1, clause2] obtain l2 :: Literal
      where "l2 el clause2" and "literalTrue l2 valuation"
      by (auto simp add: formulaTrueIffAllClausesAreTrue clauseTrueIffContainsTrueLiteral)
    have "clauseTrue (resolve clause1 clause2 literal) valuation"
    proof (cases "literal = l1")
      case False
      with l1 el clause1 
      have "l1 el (resolve clause1 clause2 literal)" 
        by (auto simp add:resolve_def)
      with ‹literalTrue l1 valuation 
      show ?thesis 
        by (auto simp add: clauseTrueIffContainsTrueLiteral)
    next
      case True
      from ‹model valuation [clause1, clause2] 
      have "consistent valuation" 
        by simp
      from True ‹literalTrue l1 valuation ‹literalTrue l2 valuation ‹consistent valuation 
      have "literal  opposite l2"
        by (auto simp add:inconsistentCharacterization)
      with l2 el clause2 
      have "l2 el (resolve clause1 clause2 literal)"
        by (auto simp add:resolve_def)
      with ‹literalTrue l2 valuation 
      show ?thesis
        by (auto simp add: clauseTrueIffContainsTrueLiteral)
    qed
  } 
  thus ?thesis 
    by (simp add: formulaEntailsClause_def)
qed

lemma formulaEntailsResolvent:
  fixes formula :: Formula and clause1 :: Clause and clause2 :: Clause
  assumes "formulaEntailsClause formula clause1" and "formulaEntailsClause formula clause2"
  shows "formulaEntailsClause formula (resolve clause1 clause2 literal)"
proof -
  {
    fix valuation :: Valuation
    assume "model valuation formula"
    hence "consistent valuation" 
      by simp
    from ‹model valuation formula ‹formulaEntailsClause formula clause1 
    have "clauseTrue clause1 valuation"
      by (simp add:formulaEntailsClause_def)
    from ‹model valuation formula ‹formulaEntailsClause formula clause2 
    have "clauseTrue clause2 valuation"
      by (simp add:formulaEntailsClause_def)
    from ‹clauseTrue clause1 valuation ‹clauseTrue clause2 valuation ‹consistent valuation 
    have "clauseTrue (resolve clause1 clause2 literal) valuation" 
      using resolventIsEntailed
      by (auto simp add: formulaEntailsClause_def)
    with ‹consistent valuation 
    have "model valuation (resolve clause1 clause2 literal)"
      by simp
  }
  thus ?thesis
    by (simp add: formulaEntailsClause_def)
qed

lemma resolveFalseClauses:
  fixes literal :: Literal and clause1 :: Clause and clause2 :: Clause and valuation :: Valuation
  assumes 
  "clauseFalse (removeAll literal clause1) valuation" and
  "clauseFalse (removeAll (opposite literal) clause2) valuation"
  shows "clauseFalse (resolve clause1 clause2 literal) valuation"
proof -
  {
    fix l :: Literal
    assume "l el (resolve clause1 clause2 literal)"
    have "literalFalse l valuation"
    proof-
      from l el (resolve clause1 clause2 literal) 
      have "l el (removeAll literal clause1)  l el (removeAll (opposite literal) clause2)"
        unfolding resolve_def
        by simp
      thus ?thesis 
      proof
        assume "l el (removeAll literal clause1)"
        thus "literalFalse l valuation"
          using ‹clauseFalse (removeAll literal clause1) valuation
          by (simp add: clauseFalseIffAllLiteralsAreFalse)
      next
        assume "l el (removeAll (opposite literal) clause2)"
        thus "literalFalse l valuation"
          using ‹clauseFalse (removeAll (opposite literal) clause2) valuation
          by (simp add: clauseFalseIffAllLiteralsAreFalse)
      qed
    qed
  }
  thus ?thesis
    by (simp add: clauseFalseIffAllLiteralsAreFalse)
qed

(*--------------------------------------------------------------------------------*)
subsubsection‹Unit clauses›

text‹Clause is unit in a valuation if all its literals but one are false, and that one is undefined.›
definition isUnitClause :: "Clause  Literal  Valuation  bool"
where
"isUnitClause uClause uLiteral valuation == 
   uLiteral el uClause  
   ¬ (literalTrue uLiteral valuation)  
   ¬ (literalFalse uLiteral valuation)  
   ( literal. literal el uClause  literal  uLiteral  literalFalse literal valuation)"


lemma unitLiteralIsEntailed:
  fixes uClause :: Clause and uLiteral :: Literal and formula :: Formula and valuation :: Valuation
  assumes "isUnitClause uClause uLiteral valuation" and "formulaEntailsClause formula uClause"
  shows "formulaEntailsLiteral (formula @ val2form valuation) uLiteral"
proof -
  {
    fix valuation'
    assume "model valuation' (formula @ val2form valuation)"
    hence "consistent valuation'"
      by simp
    from ‹model valuation' (formula @ val2form valuation) 
    have "formulaTrue formula valuation'" and "formulaTrue (val2form valuation) valuation'"
      by (auto simp add:formulaTrueAppend)
    from ‹formulaTrue formula valuation' ‹consistent valuation' ‹formulaEntailsClause formula uClause 
    have "clauseTrue uClause valuation'"
      by (simp add:formulaEntailsClause_def)
    then obtain l :: Literal
      where "l el uClause" "literalTrue l valuation'"
      by (auto simp add: clauseTrueIffContainsTrueLiteral)
    hence "literalTrue uLiteral valuation'" 
    proof (cases "l = uLiteral")
      case True
      with ‹literalTrue l valuation' 
      show ?thesis
        by simp
    next
      case False
      with l el uClause ‹isUnitClause uClause uLiteral valuation 
      have "literalFalse l valuation"
        by (simp add: isUnitClause_def)
      from ‹formulaTrue (val2form valuation) valuation' 
      have " literal :: Literal. literal el valuation  literal el valuation'"
        using val2formFormulaTrue [of "valuation" "valuation'"]
        by simp
      with ‹literalFalse l valuation 
      have "literalFalse l valuation'"
        by auto
      with ‹literalTrue l valuation' ‹consistent valuation' 
      have "False"
        by (simp add:inconsistentCharacterization)
      thus ?thesis ..
    qed
  }
  thus ?thesis
    by (simp add: formulaEntailsLiteral_def)
qed

lemma isUnitClauseRemoveAllUnitLiteralIsFalse: 
  fixes uClause :: Clause and uLiteral :: Literal and valuation :: Valuation
  assumes "isUnitClause uClause uLiteral valuation"
  shows "clauseFalse (removeAll uLiteral uClause) valuation"
proof -
  {
    fix literal :: Literal
    assume "literal el (removeAll uLiteral uClause)"
    hence "literal el uClause" and "literal  uLiteral"
      by auto
    with ‹isUnitClause uClause uLiteral valuation 
    have "literalFalse literal valuation"
      by (simp add: isUnitClause_def)
  }
  thus ?thesis 
    by (simp add: clauseFalseIffAllLiteralsAreFalse)
qed

lemma isUnitClauseAppendValuation:
  assumes "isUnitClause uClause uLiteral valuation" "l  uLiteral" "l  opposite uLiteral"
  shows "isUnitClause uClause uLiteral (valuation @ [l])"
using assms
unfolding isUnitClause_def
by auto

lemma containsTrueNotUnit:
assumes
  "l el c" and "literalTrue l v" and "consistent v"
shows
  "¬ ( ul. isUnitClause c ul v)"
using assms
unfolding isUnitClause_def
by (auto simp add: inconsistentCharacterization)

lemma unitBecomesFalse:
assumes
  "isUnitClause uClause uLiteral valuation" 
shows
  "clauseFalse uClause (valuation @ [opposite uLiteral])"
using assms
using isUnitClauseRemoveAllUnitLiteralIsFalse[of "uClause" "uLiteral" "valuation"]
by (auto simp add: clauseFalseIffAllLiteralsAreFalse)


(*--------------------------------------------------------------------------------*)
subsubsection‹Reason clauses›

text‹A clause is @{term reason} for unit propagation of a given literal if it was a unit clause before it 
  is asserted, and became true when it is asserted.›
  
definition
isReason::"Clause  Literal  Valuation  bool"
where
"(isReason clause literal valuation) ==
  (literal el clause)  
  (clauseFalse (removeAll literal clause) valuation) 
  ( literal'. literal' el (removeAll literal clause) 
        precedes (opposite literal') literal valuation  opposite literal'  literal)"

lemma isReasonAppend: 
  fixes clause :: Clause and literal :: Literal and valuation :: Valuation and valuation' :: Valuation
  assumes "isReason clause literal valuation" 
  shows "isReason clause literal (valuation @ valuation')"
proof -
  from assms 
  have "literal el clause" and 
    "clauseFalse (removeAll literal clause) valuation" (is "?false valuation") and
    " literal'. literal' el (removeAll literal clause)  
          precedes (opposite literal') literal valuation  opposite literal'  literal" (is "?precedes valuation")
    unfolding isReason_def
    by auto
  moreover
  from  ?false valuation 
  have "?false (valuation @ valuation')"
    by (rule clauseFalseAppendValuation)
  moreover
  from  ?precedes valuation 
  have "?precedes (valuation @ valuation')"
    by (simp add:precedesAppend)
  ultimately 
  show ?thesis
    unfolding isReason_def
    by auto
qed

lemma isUnitClauseIsReason: 
  fixes uClause :: Clause and uLiteral :: Literal and valuation :: Valuation
  assumes "isUnitClause uClause uLiteral valuation" "uLiteral el valuation'"
  shows "isReason uClause uLiteral (valuation @ valuation')"
proof -
  from assms 
  have "uLiteral el uClause" and "¬ literalTrue uLiteral valuation" and "¬ literalFalse uLiteral valuation"
    and " literal. literal el uClause  literal  uLiteral  literalFalse literal valuation"
    unfolding isUnitClause_def
    by auto
  hence "clauseFalse (removeAll uLiteral uClause) valuation" 
    by (simp add: clauseFalseIffAllLiteralsAreFalse)
  hence "clauseFalse (removeAll uLiteral uClause) (valuation @ valuation')"
    by (simp add: clauseFalseAppendValuation)
  moreover
  have " literal'. literal' el (removeAll uLiteral uClause)  
    precedes (opposite literal') uLiteral (valuation @ valuation')  (opposite literal')  uLiteral"
  proof -
    {
      fix literal' :: Literal
      assume "literal' el (removeAll uLiteral uClause)"
      with ‹clauseFalse (removeAll uLiteral uClause) valuation 
      have "literalFalse literal' valuation"
        by (simp add:clauseFalseIffAllLiteralsAreFalse)
      with ¬ literalTrue uLiteral valuation ¬ literalFalse uLiteral valuation
      have "precedes (opposite literal') uLiteral (valuation @ valuation')  (opposite literal')  uLiteral"
        using uLiteral el valuation'
        using precedesMemberHeadMemberTail [of "opposite literal'" "valuation" "uLiteral" "valuation'"]
        by auto
    }
    thus ?thesis 
      by simp
  qed
  ultimately
  show ?thesis using uLiteral el uClause
    by (auto simp add: isReason_def)
qed

lemma isReasonHoldsInPrefix: 
  fixes prefix :: Valuation and valuation :: Valuation and clause :: Clause and literal :: Literal
  assumes 
  "literal el prefix" and 
  "isPrefix prefix valuation" and 
  "isReason clause literal valuation"
  shows 
  "isReason clause literal prefix"
proof -
  from ‹isReason clause literal valuation 
  have
    "literal el clause" and 
    "clauseFalse (removeAll literal clause) valuation" (is "?false valuation") and
    " literal'. literal' el (removeAll literal clause)  
         precedes (opposite literal') literal valuation  opposite literal'  literal" (is "?precedes valuation")
    unfolding isReason_def
    by auto
  {
    fix literal' :: Literal
    assume "literal' el (removeAll literal clause)"
    with ?precedes valuation 
    have "precedes (opposite literal') literal valuation" "(opposite literal')  literal"
      by auto
    with literal el prefix ‹isPrefix prefix valuation
    have "precedes (opposite literal') literal prefix  (opposite literal')  literal" 
      using laterInPrefixRetainsPrecedes [of "prefix" "valuation" "opposite literal'" "literal"]
      by auto
  } 
  note * = this
  hence "?precedes prefix"
    by auto
  moreover
  have "?false prefix" 
  proof -
    {
      fix literal' :: Literal
      assume "literal' el (removeAll literal clause)"
      from literal' el (removeAll literal clause) * 
      have "precedes (opposite literal') literal prefix"
        by simp
      with literal el prefix 
      have "literalFalse literal' prefix"
        unfolding precedes_def
        by (auto split: if_split_asm)
    }
    thus ?thesis
      by (auto simp add:clauseFalseIffAllLiteralsAreFalse)
  qed
  ultimately
  show ?thesis using literal el clause
    unfolding isReason_def
    by auto
qed


(*--------------------------------------------------------------------------------*)
subsubsection‹Last asserted literal of a list›

text@{term lastAssertedLiteral} from a list is the last literal from a clause that is asserted in 
  a valuation.›
definition 
isLastAssertedLiteral::"Literal  Literal list  Valuation  bool"
where
"isLastAssertedLiteral literal clause valuation ==
  literal el clause  
  literalTrue literal valuation  
  ( literal'. literal' el clause  literal'  literal  ¬ precedes literal literal' valuation)"

text‹Function that gets the last asserted literal of a list - specified only by its postcondition.›
definition
getLastAssertedLiteral :: "Literal list  Valuation  Literal"
where
"getLastAssertedLiteral clause valuation == 
   last (filter (λ l::Literal. l el clause) valuation)"

lemma getLastAssertedLiteralCharacterization:
assumes
  "clauseFalse clause valuation"
  "clause  []"
  "uniq valuation"
shows
  "isLastAssertedLiteral (getLastAssertedLiteral (oppositeLiteralList clause) valuation) (oppositeLiteralList clause) valuation"
proof-
  let ?oppc = "oppositeLiteralList clause"
  let ?l = "getLastAssertedLiteral ?oppc valuation"
  let ?f = "filter (λ l. l el ?oppc) valuation"

  have "?oppc  []" 
    using clause  []
    using oppositeLiteralListNonempty[of "clause"]
    by simp
  then obtain l'::Literal
    where "l' el ?oppc"
    by force
  
  have " l::Literal. l el ?oppc  l el valuation"
  proof
    fix l::Literal
    show "l el ?oppc  l el valuation"
    proof
      assume "l el ?oppc"
      hence "opposite l el clause"
        using literalElListIffOppositeLiteralElOppositeLiteralList[of "l" "?oppc"]
        by simp
      thus "l el valuation"
        using ‹clauseFalse clause valuation
        using clauseFalseIffAllLiteralsAreFalse[of "clause" "valuation"]
        by auto
    qed
  qed
  hence "l' el valuation"
    using l' el ?oppc
    by simp
  hence "l' el ?f"
    using l' el ?oppc
    by simp
  hence "?f  []"
    using set_empty[of "?f"]
    by auto
  hence "last ?f el ?f"
    using last_in_set[of "?f"]
    by simp
  hence "?l el ?oppc" "literalTrue ?l valuation"
    unfolding getLastAssertedLiteral_def
    by auto
  moreover
  have "literal'. literal' el ?oppc  literal'  ?l 
                    ¬ precedes ?l literal' valuation"
  proof
    fix literal'
    show "literal' el ?oppc  literal'  ?l  ¬ precedes ?l literal' valuation"
    proof
      assume "literal' el ?oppc  literal'  ?l"
      show "¬ precedes ?l literal' valuation"
      proof (cases "literalTrue literal' valuation")
        case False
        thus ?thesis
          unfolding precedes_def
          by simp
      next
        case True
        with literal' el ?oppc  literal'  ?l
        have "literal' el ?f"
          by simp
        have "uniq ?f"
          using ‹uniq valuation
          by (simp add: uniqDistinct)
        hence "¬ precedes ?l literal' ?f"
          using lastPrecedesNoElement[of "?f"]
          using literal' el ?oppc  literal'  ?l
          unfolding getLastAssertedLiteral_def
          by auto
        thus ?thesis
          using precedesFilter[of "?l" "literal'" "valuation" "λ l. l el ?oppc"]
          using literal' el ?oppc  literal'  ?l
          using ?l el ?oppc
          by auto
      qed
    qed
  qed
  ultimately
  show ?thesis
    unfolding isLastAssertedLiteral_def
    by simp
qed

lemma lastAssertedLiteralIsUniq: 
  fixes literal :: Literal and literal' :: Literal and literalList :: "Literal list" and valuation :: Valuation
  assumes 
  lastL: "isLastAssertedLiteral literal  literalList valuation" and
  lastL': "isLastAssertedLiteral literal' literalList valuation"
  shows "literal = literal'"
using assms
proof -
  from lastL have *: 
    "literal el literalList"  
    " l. l el literalList  l  literal  ¬  precedes literal l valuation" 
    and
    "literalTrue literal valuation"  
    by (auto simp add: isLastAssertedLiteral_def)
  from lastL' have **: 
    "literal' el literalList"
    " l. l el literalList  l  literal'  ¬  precedes literal' l valuation"
    and
    "literalTrue literal' valuation"
    by (auto simp add: isLastAssertedLiteral_def)
  {
    assume "literal'  literal"
    with * ** have "¬ precedes literal literal' valuation" and "¬ precedes literal' literal valuation"
      by auto
    with ‹literalTrue literal valuation ‹literalTrue literal' valuation 
    have "False"
      using precedesTotalOrder[of "literal" "valuation" "literal'"]
      unfolding precedes_def
      by simp
  }
  thus ?thesis
    by auto
qed

lemma isLastAssertedCharacterization: 
  fixes literal :: Literal and literalList :: "Literal list" and v :: Valuation
  assumes "isLastAssertedLiteral literal (oppositeLiteralList literalList) valuation"
  shows "opposite literal el literalList" and "literalTrue literal valuation"
proof -
  from assms have
    *: "literal el (oppositeLiteralList literalList)" and **: "literalTrue literal valuation"  
    by (auto simp add: isLastAssertedLiteral_def)
  from * show "opposite literal el literalList"
    using literalElListIffOppositeLiteralElOppositeLiteralList [of "literal" "oppositeLiteralList literalList"]
    by simp
  from ** show "literalTrue literal valuation" 
    by simp
qed

lemma isLastAssertedLiteralSubset:
assumes
  "isLastAssertedLiteral l c M"
  "set c'  set c"
  "l el c'"
shows
  "isLastAssertedLiteral l c' M"
using assms
unfolding isLastAssertedLiteral_def
by auto

lemma lastAssertedLastInValuation: 
  fixes literal :: Literal and literalList :: "Literal list" and valuation :: Valuation
  assumes "literal el literalList" and "¬ literalTrue literal valuation" 
  shows "isLastAssertedLiteral literal literalList (valuation @ [literal])"
proof -
  have "literalTrue literal [literal]" 
    by simp
  hence "literalTrue literal (valuation @ [literal])"
    by simp
  moreover
  have " l. l el literalList  l  literal  ¬  precedes literal l (valuation @ [literal])"
  proof -
    {
      fix l
      assume "l el literalList" "l  literal"
      have "¬ precedes literal l (valuation @ [literal])" 
      proof (cases "literalTrue l valuation")
        case False
        with l  literal 
        show ?thesis
          unfolding precedes_def
          by simp
      next
        case True
        from ¬ literalTrue literal valuation ‹literalTrue literal [literal] ‹literalTrue l valuation 
        have "precedes l literal (valuation @ [literal])"
          using precedesMemberHeadMemberTail[of "l" "valuation" "literal" "[literal]"]
          by auto
        with l  literal ‹literalTrue l valuation ‹literalTrue literal [literal]
        show ?thesis
          using precedesAntisymmetry[of "l" "valuation @ [literal]" "literal"]
          unfolding precedes_def
          by auto
      qed
    } thus ?thesis 
      by simp
  qed
  ultimately
  show ?thesis using literal el literalList
    by (simp add:isLastAssertedLiteral_def)
qed

end

Theory Trail

(*    Title:              SATSolverVerification/Trail.thy
      Author:             Filip Maric
      Maintainer:         Filip Maric <filip at matf.bg.ac.yu>
*)

section‹Trail datatype definition and its properties›

theory Trail
imports MoreList
begin

text‹Trail is a list in which some elements can be marked.›
type_synonym 'a Trail = "('a*bool) list"

abbreviation
  element :: "('a*bool)  'a"
  where "element x == fst x"

abbreviation
  marked :: "('a*bool)  bool"
  where "marked  x == snd x"

(*--------------------------------------------------------------------------------*)
subsection‹Trail elements›

text‹Elements of the trail with marks removed›
primrec
elements              :: "'a Trail  'a list"
where
  "elements [] = []"
| "elements (h#t) = (element h) # (elements t)"

lemma
"elements t = map fst t"
by (induct t) auto

lemma eitherMarkedOrNotMarkedElement: 
  shows "a = (element a, True)  a = (element a, False)"
by (cases a) auto

lemma eitherMarkedOrNotMarked:
  assumes "e  set (elements M)"
  shows "(e, True)  set M  (e, False)  set M"
using assms
proof (induct M)
  case (Cons m M')
  thus ?case
    proof (cases "e = element m")
      case True
      thus ?thesis
        using eitherMarkedOrNotMarkedElement [of "m"]
        by auto
    next
      case False
      with Cons
      show ?thesis
        by auto
    qed
qed simp

lemma elementMemElements [simp]:
  assumes "x  set M"
  shows "element x  set (elements M)"
using assms
by (induct M) (auto split: if_split_asm)

lemma elementsAppend [simp]:
  shows "elements (a @ b) = elements a @ elements b"
by (induct a) auto

lemma elementsEmptyIffTrailEmpty [simp]:
  shows "(elements list = []) = (list = [])"
by (induct list) auto

lemma elementsButlastTrailIsButlastElementsTrail [simp]:
  shows "elements (butlast M) = butlast (elements M)"
by (induct M) auto

lemma elementLastTrailIsLastElementsTrail [simp]:
  assumes "M  []"
  shows "element (last M) = last (elements M)" 
using assms
by (induct M) auto

lemma isPrefixElements:
  assumes "isPrefix a b"
  shows "isPrefix (elements a) (elements b)"
using assms
unfolding isPrefix_def
by auto

lemma prefixElementsAreTrailElements:
  assumes 
  "isPrefix p M" 
  shows 
  "set (elements p)  set (elements M)"
using assms
unfolding isPrefix_def
by auto

lemma uniqElementsTrailImpliesUniqElementsPrefix:
  assumes 
  "isPrefix p M" and "uniq (elements M)"
  shows
  "uniq (elements p)"
proof-
  from ‹isPrefix p M
  obtain s 
    where "M = p @ s"
    unfolding isPrefix_def
    by auto
  with ‹uniq (elements M)
  show ?thesis
    using uniqAppend[of "elements p" "elements s"]
    by simp
qed

lemma [simp]: 
  assumes "(e, d)  set M"
  shows "e  set (elements M)"
  using assms
  by (induct M) auto

lemma uniqImpliesExclusiveTrueOrFalse:
  assumes
  "(e, d)  set M" and "uniq (elements M)"
  shows
  "¬ (e, ¬ d)  set M"
using assms
proof (induct M)
  case (Cons m M')
  {
    assume "(e, d) = m"
    hence "(e, ¬ d)  m"
      by auto
    from (e, d) = m ‹uniq (elements (m # M'))
    have "¬ (e, d)  set M'"
      by (auto simp add: uniqAppendIff)
    with Cons
    have ?case
      by (auto split: if_split_asm)
  }
  moreover
  {
    assume "(e, ¬ d) = m"
    hence "(e, d)  m"
      by auto
    from (e, ¬ d) = m ‹uniq (elements (m # M'))
    have "¬ (e, ¬ d)  set M'"
      by (auto simp add: uniqAppendIff)
    with Cons
    have ?case
      by (auto split: if_split_asm)
  }
  moreover
  {
    assume "(e, d)  m" "(e, ¬ d)  m"
    from (e, d)  m (e, d)  set (m # M') have 
      "(e, d)  set M'"
      by simp
    with ‹uniq (elements (m # M')) Cons(1)
    have "¬ (e, ¬ d)  set M'"
      by simp
    with (e, ¬ d)  m
    have ?case
      by simp
  }
  moreover 
  {
    have "(e, d) = m  (e, ¬ d) = m  (e, d)  m  (e, ¬ d)  m"
      by auto
  }
  ultimately
  show ?case
    by auto
qed simp

(*--------------------------------------------------------------------------------*)
subsection‹Marked trail elements›

primrec
markedElements        :: "'a Trail  'a list"
where
  "markedElements [] = []"
| "markedElements (h#t) =  (if (marked h) then (element h) # (markedElements t) else (markedElements t))"

lemma
"markedElements t = (elements (filter snd t))"
by (induct t) auto

lemma markedElementIsMarkedTrue: 
  shows "(m  set (markedElements M)) = ((m, True)  set M)"
by (induct M) (auto split: if_split_asm)

lemma markedElementsAppend: 
  shows "markedElements (M1 @ M2) = markedElements M1 @ markedElements M2"
by (induct M1) auto

lemma markedElementsAreElements:
  assumes "m  set (markedElements M)"
  shows   "m  set (elements M)"
using assms markedElementIsMarkedTrue[of "m" "M"]
by auto

lemma markedAndMemberImpliesIsMarkedElement:
  assumes "marked m" "m  set M"
  shows "(element m)  set (markedElements M)"
proof-
  have "m = (element m, marked m)"
    by auto
  with ‹marked m 
  have "m = (element m, True)"
    by simp
  with m  set M have
    "(element m, True)  set M"
    by simp
  thus ?thesis
    using markedElementIsMarkedTrue [of "element m" "M"]
    by simp
qed

lemma markedElementsPrefixAreMarkedElementsTrail:
  assumes "isPrefix p M" "m  set (markedElements p)"
  shows "m  set (markedElements M)"
proof-
  from m  set (markedElements p) 
  have "(m, True)  set p"
    by (simp add: markedElementIsMarkedTrue)
  with ‹isPrefix p M
  have "(m, True)  set M"
    using prefixIsSubset[of "p" "M"]
    by auto
  thus ?thesis
    by (simp add: markedElementIsMarkedTrue)
qed

lemma markedElementsTrailMemPrefixAreMarkedElementsPrefix:
  assumes 
  "uniq (elements M)" and
  "isPrefix p M" and
  "m  set (elements p)" and
  "m  set (markedElements M)" 
  shows
  "m  set (markedElements p)"
proof-
  from m  set (markedElements M) have "(m, True)  set M"
    by (simp add: markedElementIsMarkedTrue)
  with ‹uniq (elements M) m  set (elements p)
  have "(m, True)  set p"
  proof-
    {
      assume "(m, False)  set p"
      with ‹isPrefix p M
      have "(m, False)  set M"
        using prefixIsSubset[of "p" "M"]
        by auto
      with (m, True)  set M ‹uniq (elements M)
      have False
        using uniqImpliesExclusiveTrueOrFalse[of "m" "True" "M"]
        by simp
    }
    with m  set (elements p)
    show ?thesis
      using eitherMarkedOrNotMarked[of "m" "p"]
      by auto
  qed
  thus ?thesis
    using markedElementIsMarkedTrue[of "m" "p"]
    by simp
qed

(*--------------------------------------------------------------------------------*)
subsection‹Prefix before/upto a trail element›

text‹Elements of the trail before the first occurrence of a given element - not incuding it›
primrec
prefixBeforeElement  :: "'a  'a Trail  'a Trail"
where
  "prefixBeforeElement e [] = []"
| "prefixBeforeElement e (h#t) = 
 (if (element h) = e then
     []
  else
     (h # (prefixBeforeElement e t))
 )"

lemma "prefixBeforeElement e t = takeWhile (λ e'. element e'  e) t"
by (induct t) auto

lemma "prefixBeforeElement e t = take (firstPos e (elements t)) t"
by (induct t) auto

text‹Elements of the trail before the first occurrence of a given element - incuding it›
primrec
prefixToElement  :: "'a  'a Trail  'a Trail"
where
  "prefixToElement e [] = []"
| "prefixToElement e (h#t) = 
   (if (element h) = e then
      [h]
    else
      (h # (prefixToElement e t))
   )"

lemma "prefixToElement e t = take ((firstPos e (elements t)) + 1) t"
by (induct t) auto


lemma isPrefixPrefixToElement:
  shows "isPrefix (prefixToElement e t) t"
unfolding isPrefix_def
by (induct t) auto

lemma isPrefixPrefixBeforeElement:
  shows "isPrefix (prefixBeforeElement e t) t"
unfolding isPrefix_def
by (induct t) auto

lemma prefixToElementContainsTrailElement:
  assumes "e  set (elements M)"
  shows "e  set (elements (prefixToElement e M))"
using assms
by (induct M) auto

lemma prefixBeforeElementDoesNotContainTrailElement:
  assumes "e  set (elements M)"
  shows "e  set (elements (prefixBeforeElement e M))"
using assms
by (induct M) auto

lemma prefixToElementAppend: 
  shows "prefixToElement e (M1 @ M2) = 
            (if e  set (elements M1) then 
                prefixToElement e M1
             else   
                M1 @ prefixToElement e M2
             )"
by (induct M1) auto


lemma prefixToElementToPrefixElement:
  assumes
  "isPrefix p M" and "e  set (elements p)"
  shows
  "prefixToElement e M = prefixToElement e p"
using assms
unfolding isPrefix_def
proof (induct p arbitrary: M)
  case (Cons a p')
  then obtain s 
    where "(a # p') @ s = M"
    by auto
  show ?case
  proof (cases "(element a) = e")
    case True
    from True (a # p') @ s = M have "prefixToElement e M = [a]"
      by auto
    moreover
    from True have "prefixToElement e (a # p') = [a]"
      by auto
    ultimately
    show ?thesis
      by simp
  next
    case False
    from False (a # p') @ s = M have "prefixToElement e M = a # prefixToElement e (p' @ s)"
      by auto
    moreover
    from False have "prefixToElement e (a # p') = a # prefixToElement e p'"
      by simp
    moreover
    from False e  set (elements (a # p')) have "e  set (elements p')"
      by simp
    have "? s . (p' @ s = p' @ s)"
      by simp
    from e  set (elements p')  ? s. (p' @ s = p' @ s) 
      have "prefixToElement e (p' @ s) = prefixToElement e p'"
      using Cons(1) [of "p' @ s"]
      by simp
    ultimately show ?thesis
      by simp
  qed
qed simp

(*--------------------------------------------------------------------------------*)
subsection‹Marked elements upto a given trail element›

text‹Marked elements of the trail upto the given element (which is also included if it is marked)›
definition
markedElementsTo :: "'a  'a Trail  'a list"
where
"markedElementsTo e t = markedElements (prefixToElement e t)"

lemma markedElementsToArePrefixOfMarkedElements:
  shows "isPrefix (markedElementsTo e M) (markedElements M)"
unfolding isPrefix_def
unfolding markedElementsTo_def
by (induct M) auto

lemma markedElementsToAreMarkedElements: 
  assumes "m  set (markedElementsTo e M)"
  shows "m  set (markedElements M)"
using assms
using markedElementsToArePrefixOfMarkedElements[of "e" "M"]
using prefixIsSubset
by auto

lemma markedElementsToNonMemberAreAllMarkedElements:
  assumes "e  set (elements M)"
  shows "markedElementsTo e M = markedElements M" 
using assms
unfolding markedElementsTo_def
by (induct M) auto

lemma markedElementsToAppend: 
  shows "markedElementsTo e (M1 @ M2) = 
          (if e  set (elements M1) then 
                 markedElementsTo e M1
           else 
                 markedElements M1 @ markedElementsTo e M2
          )"
unfolding markedElementsTo_def
by (auto simp add: prefixToElementAppend markedElementsAppend)

lemma markedElementsEmptyImpliesMarkedElementsToEmpty: 
  assumes "markedElements M = []"
  shows "markedElementsTo e M = []"
using assms
using markedElementsToArePrefixOfMarkedElements [of "e" "M"]
unfolding isPrefix_def
by auto

lemma markedElementIsMemberOfItsMarkedElementsTo: 
  assumes
  "uniq (elements M)" and "marked e" and "e  set M"
  shows 
  "element e  set (markedElementsTo (element e) M)"
using assms
unfolding markedElementsTo_def
by (induct M) (auto split: if_split_asm)

lemma markedElementsToPrefixElement: 
  assumes "isPrefix p M" and "e  set (elements p)"
  shows "markedElementsTo e M = markedElementsTo e p"
unfolding markedElementsTo_def
using assms
by (simp add: prefixToElementToPrefixElement)


(*--------------------------------------------------------------------------------*)
subsection‹Last marked element in a trail›

definition
lastMarked :: "'a Trail  'a"
where
"lastMarked t = last (markedElements t)"

lemma lastMarkedIsMarkedElement: 
  assumes "markedElements M  []" 
  shows "lastMarked M  set (markedElements M)"
using assms
unfolding lastMarked_def
by simp

lemma removeLastMarkedFromMarkedElementsToLastMarkedAreAllMarkedElementsInPrefixLastMarked: 
  assumes
  "markedElements M  []"
  shows
  "removeAll (lastMarked M) (markedElementsTo (lastMarked M) M) = markedElements (prefixBeforeElement (lastMarked M) M)"
using assms
unfolding lastMarked_def
unfolding markedElementsTo_def
by (induct M) auto

lemma markedElementsToLastMarkedAreAllMarkedElements:
  assumes
  "uniq (elements M)" and "markedElements M  []"
  shows
  "markedElementsTo (lastMarked M) M = markedElements M"
using assms
unfolding lastMarked_def
unfolding markedElementsTo_def
by (induct M) (auto simp add: markedElementsAreElements)

lemma lastTrailElementMarkedImpliesMarkedElementsToLastElementAreAllMarkedElements:
  assumes
  "marked (last M)" and "last (elements M)  set (butlast (elements M))"
  shows
  "markedElementsTo (last (elements M)) M = markedElements M"
using assms
unfolding markedElementsTo_def
by (induct M) auto

lemma lastMarkedIsMemberOfItsMarkedElementsTo: 
  assumes
  "uniq (elements M)" and "markedElements M  []"
  shows
  "lastMarked M  set (markedElementsTo (lastMarked M) M)"
using assms
using markedElementsToLastMarkedAreAllMarkedElements [of "M"]
using lastMarkedIsMarkedElement [of "M"]
by auto

lemma lastTrailElementNotMarkedImpliesMarkedElementsToLAreMarkedElementsToLInButlastTrail: 
  assumes "¬ marked (last M)"
  shows "markedElementsTo e M = markedElementsTo e (butlast M)"
using assms
unfolding markedElementsTo_def
by (induct M) auto


(*--------------------------------------------------------------------------------*)
subsection‹Level of a trail element›

text‹Level of an element is the number of marked elements that precede it›

definition
elementLevel :: "'a  'a Trail  nat"
where
"elementLevel e t = length (markedElementsTo e t)"

lemma elementLevelMarkedGeq1:
  assumes
  "uniq (elements M)" and "e  set (markedElements M)"
  shows
  "elementLevel e M >= 1"
proof-
  from e  set (markedElements M) have "(e, True)  set M"
    by (simp add: markedElementIsMarkedTrue)
  with ‹uniq (elements M)  have "e  set (markedElementsTo e M)"
    using markedElementIsMemberOfItsMarkedElementsTo[of "M" "(e, True)"]
    by simp
  hence "markedElementsTo e M  []"
    by auto
  thus ?thesis
    unfolding elementLevel_def
    using length_greater_0_conv[of "markedElementsTo e M"]
    by arith
qed

lemma elementLevelAppend:
  assumes "a  set (elements M)"
  shows "elementLevel a M = elementLevel a (M @ M')"
using assms
unfolding elementLevel_def
by (simp add: markedElementsToAppend)


lemma elementLevelPrecedesLeq: 
  assumes
  "precedes a b (elements M)" 
  shows
  "elementLevel a M  elementLevel b M"
using assms
proof (induct M)
  case (Cons m M')
  {
    assume "a = element m"
    hence ?case
      unfolding elementLevel_def
      unfolding markedElementsTo_def
      by simp
  }
  moreover
  {
    assume "b = element m"
    {
      assume "a  b"
      hence "¬ precedes a b (b # (elements M'))"
        by (rule noElementsPrecedesFirstElement)
      with b = element m ‹precedes a b (elements (m # M'))
      have False
        by simp
    }
    hence "a = b"
      by auto
    hence ?case
      by simp
  }
  moreover 
  { 
    assume "a  element m" "b  element m"
    moreover
    from ‹precedes a b (elements (m # M'))
    have "a  set (elements (m # M'))" "b  set (elements (m # M'))"
      unfolding precedes_def
      by (auto split: if_split_asm)
    from a  element m a  set (elements (m # M'))
    have "a  set (elements M')"
      by simp
    moreover
    from b  element m b  set (elements (m # M'))
    have "b  set (elements M')"
      by simp
    ultimately
    have "elementLevel a M'  elementLevel b M'"
      using Cons
      unfolding precedes_def
      by auto
    hence ?case
      using a  element m b  element m
      unfolding elementLevel_def
      unfolding markedElementsTo_def
      by auto
  }
  ultimately
  show ?case
    by auto
next
  case Nil
  thus ?case
    unfolding precedes_def
    by simp
qed


lemma elementLevelPrecedesMarkedElementLt: 
  assumes
  "uniq (elements M)" and
  "e  d" and
  "d  set (markedElements M)" and
  "precedes e d (elements M)"
  shows
  "elementLevel e M < elementLevel d M"
using assms
proof (induct M)
  case (Cons m M')
  {
    assume "e = element m"
    moreover
    with e  d have "d  element m"
      by simp
    moreover
    from ‹uniq (elements (m # M')) d  set (markedElements (m # M'))
    have "1  elementLevel d (m # M')"
      using elementLevelMarkedGeq1[of "m # M'" "d"]
      by auto
    moreover
    from d  element m d  set (markedElements (m # M'))
    have "d  set (markedElements M')"
      by (simp split: if_split_asm)
    from ‹uniq (elements (m # M')) d  set (markedElements M')
    have "1  elementLevel d M'"
      using elementLevelMarkedGeq1[of "M'" "d"]
      by auto
    ultimately
    have ?case
      unfolding elementLevel_def
      unfolding markedElementsTo_def
      by (auto split: if_split_asm)
  }
  moreover
  {
    assume "d = element m"
    from e  d have "¬ precedes e d (d # (elements M'))"
      using noElementsPrecedesFirstElement[of "e" "d" "elements M'"]
      by simp
    with d = element m ‹precedes e d (elements (m # M'))
    have False
      by simp
    hence ?case
      by simp
  }
  moreover
  {
    assume "e  element m" "d  element m"    
    moreover
    from ‹precedes e d (elements (m # M'))
    have "e  set (elements (m # M'))" "d  set (elements (m # M'))"
      unfolding precedes_def
      by (auto split: if_split_asm)
    from e  element m e  set (elements (m # M'))
    have "e  set (elements M')"
      by simp
    moreover
    from d  element m d  set (elements (m # M'))
    have "d  set (elements M')"
      by simp
    moreover
    from d  element m d  set (markedElements (m # M'))
    have "d  set (markedElements M')"
      by (simp split: if_split_asm)
    ultimately
    have "elementLevel e M' < elementLevel d M'"
      using ‹uniq (elements (m # M')) Cons
      unfolding precedes_def
      by auto
    hence ?case
      using e  element m d  element m
      unfolding elementLevel_def
      unfolding markedElementsTo_def
      by auto
  }
  ultimately
  show ?case
    by auto
qed simp

lemma differentMarkedElementsHaveDifferentLevels:
  assumes
  "uniq (elements M)" and
  "a  set (markedElements M)" and
  "b  set (markedElements M)" and
  "a  b" 
  shows "elementLevel a M  elementLevel b M"
proof-
  from a  set (markedElements M)
  have "a  set (elements M)"
    by (simp add: markedElementsAreElements)
  moreover
  from b  set (markedElements M)
  have "b  set (elements M)"
    by (simp add: markedElementsAreElements)
  ultimately
  have "precedes a b (elements M)  precedes b a (elements M)"
    using a  b
    using precedesTotalOrder[of "a" "elements M" "b"]
    by simp
  moreover
  {
    assume "precedes a b (elements M)"
    with assms
    have ?thesis
      using elementLevelPrecedesMarkedElementLt[of "M" "a" "b"]
      by auto
  }
  moreover
  {
    assume "precedes b a (elements M)"
    with assms
    have ?thesis
      using elementLevelPrecedesMarkedElementLt[of "M" "b" "a"]
      by auto
  }
  ultimately
  show ?thesis
    by auto
qed


(* ------------------------------------------------------------------------- *)
subsection‹Current trail level›

text‹Current level is the number of marked elements in the trail›

definition
currentLevel :: "'a Trail  nat"
where
"currentLevel t = length (markedElements t)"

lemma currentLevelNonMarked: 
  shows "currentLevel M = currentLevel (M @ [(l, False)])"
by (auto simp add:currentLevel_def markedElementsAppend)

lemma currentLevelPrefix:
  assumes "isPrefix a b" 
  shows "currentLevel a <= currentLevel b"
using assms
unfolding isPrefix_def
unfolding currentLevel_def
by (auto simp add: markedElementsAppend)

lemma elementLevelLeqCurrentLevel:
  shows "elementLevel a M  currentLevel M"
proof-
  have "isPrefix (prefixToElement a M) M"
    using isPrefixPrefixToElement[of "a" "M"]
    .
  then obtain s
    where "prefixToElement a M @ s = M"
    unfolding isPrefix_def
    by auto
  hence "M = prefixToElement a M @ s"
    by (rule sym)
  hence "currentLevel M = currentLevel (prefixToElement a M @ s)"
    by simp
  hence "currentLevel M = length (markedElements (prefixToElement a M)) + length (markedElements s)"
    unfolding currentLevel_def
    by (simp add: markedElementsAppend)
  thus ?thesis
    unfolding elementLevel_def
    unfolding markedElementsTo_def
    by simp
qed

lemma elementOnCurrentLevel:
  assumes "a  set (elements M)"
  shows "elementLevel a (M @ [(a, d)]) = currentLevel  (M @ [(a, d)])"
using assms
unfolding currentLevel_def
unfolding elementLevel_def
unfolding markedElementsTo_def 
by (auto simp add: prefixToElementAppend)

(*--------------------------------------------------------------------------------*)
subsection‹Prefix to a given trail level›

text‹Prefix is made or elements of the trail up to a given element level›


primrec
prefixToLevel_aux :: "'a Trail  nat  nat  'a Trail"
where
  "(prefixToLevel_aux [] l cl) = []"
| "(prefixToLevel_aux (h#t) l cl) = 
  (if (marked h) then
    (if (cl >= l) then [] else (h # (prefixToLevel_aux t l (cl+1))))
  else
    (h # (prefixToLevel_aux t l cl))
  )"

definition
prefixToLevel :: "nat  'a Trail  'a Trail"
where
prefixToLevel_def: "(prefixToLevel l t) == (prefixToLevel_aux t l 0)"


lemma isPrefixPrefixToLevel_aux:
  shows " s. prefixToLevel_aux t l i @ s = t"
by (induct t arbitrary: i) auto

lemma isPrefixPrefixToLevel:
  shows "(isPrefix (prefixToLevel l t) t)"
using isPrefixPrefixToLevel_aux[of "t" "l"]
unfolding isPrefix_def
unfolding prefixToLevel_def
by simp

lemma currentLevelPrefixToLevel_aux: 
  assumes "l  i"
  shows "currentLevel (prefixToLevel_aux M l i) <= l - i"
using assms
proof (induct M arbitrary: i)
  case (Cons m M')
  {
    assume "marked m" "i = l"
    hence ?case
      unfolding currentLevel_def
      by simp
  }
  moreover
  {
    assume "marked m" "i < l"
    hence ?case
      using Cons(1) [of "i+1"]
      unfolding currentLevel_def
      by simp
  }
  moreover
  {
    assume "¬ marked m"
    hence ?case
      using Cons
      unfolding currentLevel_def
      by simp
  }
  ultimately
  show ?case
    using i <= l
    by auto
next
  case Nil
  thus ?case
    unfolding currentLevel_def
    by simp
qed

lemma currentLevelPrefixToLevel: 
  shows "currentLevel (prefixToLevel level M)  level"
using currentLevelPrefixToLevel_aux[of "0" "level" "M"]
unfolding prefixToLevel_def
by simp

lemma currentLevelPrefixToLevelEq_aux: 
  assumes "l  i" "currentLevel M >= l - i"
  shows "currentLevel (prefixToLevel_aux M l i) = l - i"
using assms
proof (induct M arbitrary: i)
  case (Cons m M')
  {
    assume "marked m" "i = l"
    hence ?case
      unfolding currentLevel_def
      by simp
  }
  moreover
  {
    assume "marked m" "i < l"
    hence ?case
      using Cons(1) [of "i+1"]
      using Cons(3)
      unfolding currentLevel_def
      by simp
  }
  moreover
  {
    assume "¬ marked m"
    hence ?case
      using Cons
      unfolding currentLevel_def
      by simp
  }
  ultimately
  show ?case
    using i <= l
    by auto
next
  case Nil
  thus ?case
    unfolding currentLevel_def
    by simp
qed

lemma currentLevelPrefixToLevelEq:
assumes
  "level  currentLevel M"
shows
  "currentLevel (prefixToLevel level M) = level"
using assms
unfolding prefixToLevel_def
using currentLevelPrefixToLevelEq_aux[of "0" "level" "M"]
by simp

lemma prefixToLevel_auxIncreaseAuxilaryCounter: 
  assumes "k  i"
  shows "prefixToLevel_aux M l i = prefixToLevel_aux M (l + (k - i)) k"
using assms
proof (induct M arbitrary: i k)
  case (Cons m M')
  {
    assume "¬ marked m"
    hence ?case
      using Cons(1)[of "i" "k"] Cons(2)
      by simp
  }
  moreover
  {
    assume "i  l" "marked m"
    hence ?case
      using k  i
      by simp
  }
  moreover
  {
    assume "i < l" "marked m"
    hence ?case
      using Cons(1)[of "i+1" "k+1"] Cons(2)
      by simp
  }
  ultimately
  show ?case
    by (auto split: if_split_asm)
qed simp

lemma isPrefixPrefixToLevel_auxLowerLevel:
  assumes "i  j"
  shows "isPrefix (prefixToLevel_aux M i k) (prefixToLevel_aux M j k)"
using assms
by (induct M arbitrary: k) (auto simp add:isPrefix_def)

lemma isPrefixPrefixToLevelLowerLevel:
assumes "level < level'"
shows "isPrefix (prefixToLevel level M) (prefixToLevel level' M)"
using assms
unfolding prefixToLevel_def
using isPrefixPrefixToLevel_auxLowerLevel[of "level" "level'" "M" "0"]
by simp

lemma prefixToLevel_auxPrefixToLevel_auxHigherLevel: 
  assumes "i  j"
  shows "prefixToLevel_aux a i k = prefixToLevel_aux (prefixToLevel_aux a j k) i k"
using assms
by (induct a arbitrary: k) auto

lemma prefixToLevelPrefixToLevelHigherLevel: 
  assumes "level  level'"
  shows "prefixToLevel level M = prefixToLevel level (prefixToLevel level' M)"
using assms
unfolding prefixToLevel_def
using prefixToLevel_auxPrefixToLevel_auxHigherLevel[of "level" "level'" "M" "0"]
by simp

lemma prefixToLevelAppend_aux1:
  assumes
  "l  i" and "l - i < currentLevel a"
  shows 
  "prefixToLevel_aux (a @ b) l i = prefixToLevel_aux a l i"
using assms
proof (induct a arbitrary: i)
  case (Cons a a')
  {
    assume "¬ marked a"
    hence ?case
      using Cons(1)[of "i"] i  l l - i < currentLevel (a # a')
      unfolding currentLevel_def
      by simp
  }
  moreover
  {
    assume "marked a" "l = i"
    hence ?case
      by simp
  }
  moreover
  {
    assume "marked a" "l > i"
    hence ?case
      using Cons(1)[of "i + 1"] i  l l - i < currentLevel (a # a')
      unfolding currentLevel_def
      by simp
  }
  ultimately
  show ?case
    using i  l
    by auto
next
  case Nil
  thus ?case
    unfolding currentLevel_def
    by simp
qed


lemma prefixToLevelAppend_aux2: 
  assumes 
  "i  l" and "currentLevel a + i  l"
  shows "prefixToLevel_aux (a @ b) l i = a @ prefixToLevel_aux b l (i + (currentLevel a))"
using assms
proof (induct a arbitrary: i)
  case (Cons a a')
  {
    assume "¬ marked a"
    hence ?case
      using Cons
      unfolding currentLevel_def
      by simp
  }
  moreover
  {
    assume "marked a" "l = i"
    hence ?case
      using (currentLevel (a # a')) + i  l
      unfolding currentLevel_def
      by simp
  }
  moreover
  {
    assume "marked a" "l > i"
    hence "prefixToLevel_aux (a' @ b) l (i + 1) = a' @ prefixToLevel_aux b l (i + 1 + currentLevel a')"
      using Cons(1) [of "i + 1"] (currentLevel (a # a')) + i  l
      unfolding currentLevel_def
      by simp
    moreover
    have "i + 1 + length (markedElements a') = i + (1 + length (markedElements a'))"
      by simp
    ultimately
    have ?case
      using ‹marked a l > i
      unfolding currentLevel_def
      by simp
  }
  ultimately
  show ?case
    using l  i
    by auto
next
  case Nil
  thus ?case
    unfolding currentLevel_def
    by simp
qed

lemma prefixToLevelAppend:
  shows "prefixToLevel level (a @ b) = 
  (if level < currentLevel a then 
      prefixToLevel level a
  else 
      a @ prefixToLevel_aux b level (currentLevel a)
  )"
proof (cases "level < currentLevel a")
  case True
  thus ?thesis
    unfolding prefixToLevel_def
    using prefixToLevelAppend_aux1[of "0" "level" "a"]
    by simp
next
  case False
  thus ?thesis
    unfolding prefixToLevel_def
    using prefixToLevelAppend_aux2[of "0" "level" "a"]
    by simp
qed

lemma isProperPrefixPrefixToLevel:
  assumes "level < currentLevel t" 
  shows " s. (prefixToLevel level t) @ s = t  s  []  (marked (hd s))"
proof-
  have "isPrefix (prefixToLevel level t) t"
    by (simp add:isPrefixPrefixToLevel)
  then obtain s::"'a Trail"
    where "(prefixToLevel level t) @ s = t"
    unfolding isPrefix_def
    by auto
  moreover
  have "s  []"
  proof-
    {
      assume "s = []"
      with (prefixToLevel level t) @ s = t 
      have "prefixToLevel level t = t"
        by simp
      hence "currentLevel (prefixToLevel level t)  level"
        using currentLevelPrefixToLevel[of "level" "t"]
        by simp
      with ‹prefixToLevel level t = t have "currentLevel t  level"
        by simp
      with level < currentLevel t have False
        by simp
    }
    thus ?thesis
      by auto
  qed
  moreover
  have "marked (hd s)"
  proof-
    {
      assume "¬ marked (hd s)"
      have "currentLevel (prefixToLevel level t)  level"
        by (simp add:currentLevelPrefixToLevel)
      from s  [] have "s = [hd s] @ (tl s)"
        by simp
      with (prefixToLevel level t) @ s = t have
        "t = (prefixToLevel level t) @ [hd s] @ (tl s)"
        by simp
      hence "(prefixToLevel level t) = (prefixToLevel level ((prefixToLevel level t) @ [hd s] @ (tl s)))"
        by simp
      also
      with ‹currentLevel (prefixToLevel level t)  level 
      have " = ((prefixToLevel level t) @ (prefixToLevel_aux ([hd s] @ (tl s)) level (currentLevel (prefixToLevel level t))))"
        by (auto simp add: prefixToLevelAppend)
      also
      have " = 
        ((prefixToLevel level t) @ (hd s) # prefixToLevel_aux (tl s) level (currentLevel (prefixToLevel level t)))"
      proof-
        from ‹currentLevel (prefixToLevel level t) <= level ¬ marked (hd s)
        have "prefixToLevel_aux ([hd s] @ (tl s)) level (currentLevel (prefixToLevel level t)) = 
          (hd s) # prefixToLevel_aux (tl s) level (currentLevel (prefixToLevel level t))"
          by simp
        thus ?thesis
          by simp
      qed
      ultimately
      have "(prefixToLevel level t) = (prefixToLevel level t) @ (hd s) # prefixToLevel_aux (tl s) level (currentLevel (prefixToLevel level t))"
        by simp
      hence "False"
        by auto
    }
    thus ?thesis
      by auto
  qed
  ultimately
  show ?thesis
    by auto
qed

lemma prefixToLevelElementsElementLevel: 
  assumes 
  "e   set (elements (prefixToLevel level M))"
  shows
  "elementLevel e M  level"
proof -
  have "elementLevel e (prefixToLevel level M)  currentLevel (prefixToLevel  level M)"
    by (simp add: elementLevelLeqCurrentLevel)
  moreover
  hence "currentLevel (prefixToLevel level M)  level"
    using currentLevelPrefixToLevel[of "level" "M"]
    by simp
  ultimately have "elementLevel e (prefixToLevel level M)  level"
    by simp
  moreover
  have "isPrefix (prefixToLevel level M) M"
    by (simp add:isPrefixPrefixToLevel)
  then obtain s
    where "(prefixToLevel level M) @ s = M"
    unfolding isPrefix_def
    by auto
  with e   set (elements (prefixToLevel level M)) 
  have "elementLevel e (prefixToLevel level M) = elementLevel e M"
    using elementLevelAppend [of "e" "prefixToLevel level M" "s"]
    by simp
  ultimately
  show ?thesis
    by simp
qed

lemma elementLevelLtLevelImpliesMemberPrefixToLevel_aux:
  assumes
  "e   set(elements M)" and
  "elementLevel e M + i  level" and
  "i  level"
  shows 
  "e   set (elements (prefixToLevel_aux M level i))"
using assms
proof (induct M arbitrary: i)
  case (Cons m M')
  thus ?case
  proof (cases "e = element m")
    case True
    thus ?thesis
      using ‹elementLevel e (m # M') + i  level
      unfolding prefixToLevel_def
      unfolding elementLevel_def
      unfolding markedElementsTo_def
      by (simp split: if_split_asm)
  next
    case False
    with e  set (elements (m # M'))
    have "e  set (elements M')"
      by simp

    show ?thesis
    proof (cases "marked m")
      case True
      with Cons e  element m
      have "(elementLevel e M') + i + 1  level"
        unfolding elementLevel_def
        unfolding markedElementsTo_def
        by (simp split: if_split_asm)
      moreover
      have "elementLevel e M'  0"
        by auto
      ultimately
      have "i + 1  level"
        by simp
      with e  set (elements M') (elementLevel e M') + i + 1  level Cons(1)[of "i+1"]
      have "e  set (elements (prefixToLevel_aux M' level (i + 1)))"
        by simp
      with e  element m i + 1  level True 
      show ?thesis
        by simp
    next
      case False
      with e  element m ‹elementLevel e (m # M') + i  level have "elementLevel e M' + i  level"
        unfolding elementLevel_def
        unfolding markedElementsTo_def
        by (simp split: if_split_asm)
      with e  set (elements M') have "e  set (elements (prefixToLevel_aux M' level i))"
        using Cons
        by (auto split: if_split_asm)
      with e  element m False show ?thesis
        by simp
    qed
  qed
qed simp

lemma elementLevelLtLevelImpliesMemberPrefixToLevel:
  assumes
  "e  set (elements M)" and
  "elementLevel e M  level"
  shows 
  "e  set (elements (prefixToLevel level M))"
using assms
using elementLevelLtLevelImpliesMemberPrefixToLevel_aux[of "e" "M" "0" "level"]
unfolding prefixToLevel_def
by simp

lemma literalNotInEarlierLevelsThanItsLevel: 
  assumes
  "level < elementLevel e M" 
  shows 
  "e  set (elements (prefixToLevel level M))"
proof-
  {
    assume "¬ ?thesis"
    hence "level  elementLevel e M"
      by (simp add: prefixToLevelElementsElementLevel)
    with level < elementLevel e M
    have False
      by simp
  }
  thus ?thesis
    by auto
qed

lemma elementLevelPrefixElement: 
  assumes "e  set (elements (prefixToLevel level M))"
  shows "elementLevel e (prefixToLevel level M) = elementLevel e M"
using assms
proof-
  have "isPrefix (prefixToLevel level M) M"
    by (simp add: isPrefixPrefixToLevel)
  then obtain s where "(prefixToLevel level M) @ s = M"
    unfolding isPrefix_def
    by auto
  with assms show ?thesis
    using elementLevelAppend[of "e" "prefixToLevel level M" "s"]
    by auto
qed

lemma currentLevelZeroTrailEqualsItsPrefixToLevelZero:
  assumes "currentLevel M = 0" 
  shows "M = prefixToLevel 0 M"
using assms
proof (induct M)
  case (Cons a M')
  show ?case
  proof-
    from Cons
    have "currentLevel M' = 0" and "markedElements M' = []" and "¬ marked a"
      unfolding currentLevel_def
      by (auto split: if_split_asm)
    thus ?thesis
      using Cons
      unfolding prefixToLevel_def
      by auto
  qed
next
  case Nil
  thus ?case
    unfolding currentLevel_def
    unfolding prefixToLevel_def
    by simp
qed

(*--------------------------------------------------------------------------------*)
subsection‹Number of literals of every trail level›

primrec
levelsCounter_aux :: "'a Trail  nat list  nat list"
where
  "levelsCounter_aux [] l = l"
| "levelsCounter_aux (h # t) l = 
    (if (marked h) then 
        levelsCounter_aux t (l @ [1]) 
     else
        levelsCounter_aux t (butlast l @ [Suc (last l)])
    )"

definition
levelsCounter :: "'a Trail  nat list"
where
"levelsCounter t = levelsCounter_aux t [0]"


lemma levelsCounter_aux_startIrellevant: 
  " y. y  []  levelsCounter_aux a (x @ y) = (x @ levelsCounter_aux a y)"
by (induct a) (auto simp add: butlastAppend)

lemma levelsCounter_auxSuffixContinues: " l. levelsCounter_aux (a @ b) l = levelsCounter_aux b (levelsCounter_aux a l)"
by (induct a) auto

lemma levelsCounter_auxNotEmpty: " l. l  []  levelsCounter_aux a l  []"
by (induct a) auto

lemma levelsCounter_auxIncreasesFirst: 
" m n l1 l2. levelsCounter_aux a (m # l1) = n # l2  m <= n"
proof (induct "a")
  case Nil
  {
    fix m::nat and n::nat and l1::"nat list" and l2::"nat list"
    assume "levelsCounter_aux [] (m # l1) = n # l2"
    hence "m = n"
      by simp
  }
  thus ?case
    by simp
next
  case (Cons a list)
  {
    fix m::nat and n::nat and l1::"nat list" and l2::"nat list"
    assume "levelsCounter_aux (a # list) (m # l1) = n # l2"
    have "m <= n"
    proof (cases "marked a")
      case True
      with ‹levelsCounter_aux (a # list) (m # l1) = n # l2 
      have "levelsCounter_aux list (m # l1 @ [Suc 0]) = n # l2"
        by simp
      with Cons
      show ?thesis
        by auto
    next
      case False
      show ?thesis 
      proof (cases "l1 = []")
        case True
        with ¬ marked a ‹levelsCounter_aux (a # list) (m # l1) = n # l2 
        have "levelsCounter_aux list [Suc m] = n # l2"
          by simp
        with Cons
        have "Suc m <= n"
          by auto
        thus ?thesis
          by simp
      next
        case False
        with ¬ marked a ‹levelsCounter_aux (a # list) (m # l1) = n # l2 
        have "levelsCounter_aux list (m # butlast l1 @ [Suc (last l1)]) = n # l2"
          by simp
        with Cons
        show ?thesis
          by auto
      qed
    qed
  }
  thus ?case
    by simp
qed

lemma levelsCounterPrefix:
  assumes "(isPrefix p a)"
  shows "? rest. rest  []  levelsCounter a = butlast (levelsCounter p) @ rest  last (levelsCounter p)  hd rest"
proof-
  from assms
  obtain s :: "'a Trail" where "p @ s = a"
    unfolding isPrefix_def
    by auto
  from p @ s = a have "levelsCounter a = levelsCounter (p @ s)"
    by simp
  show ?thesis
  proof (cases "s = []")
    case True
    have "(levelsCounter a) = (butlast (levelsCounter p)) @ [last (levelsCounter p)]  
      (last (levelsCounter p)) <= hd [last (levelsCounter p)]"
      using p @ s = a s = []
      unfolding levelsCounter_def
      using levelsCounter_auxNotEmpty[of "p"]
      by auto
    thus ?thesis
      by auto
  next
    case False
    show ?thesis
    proof (cases "marked (hd s)")
      case True
      from p @ s = a have "levelsCounter a = levelsCounter (p @ s)"
        by simp
      also
      have " = levelsCounter_aux s (levelsCounter_aux p [0])"
        unfolding levelsCounter_def
        by (simp add: levelsCounter_auxSuffixContinues)
      also
      have " = levelsCounter_aux (tl s) ((levelsCounter_aux p [0]) @ [1])"
      proof-
        from s  [] have "s = hd s # tl s"
          by simp
        then have "levelsCounter_aux s (levelsCounter_aux p [0]) = levelsCounter_aux (hd s # tl s) (levelsCounter_aux p [0])"
          by simp
        with ‹marked (hd s) show ?thesis
          by simp
      qed
      also
      have " = levelsCounter_aux p [0] @ (levelsCounter_aux (tl s) [1])"
        by (simp add: levelsCounter_aux_startIrellevant)
      finally 
      have "levelsCounter a = levelsCounter p @ (levelsCounter_aux (tl s) [1])"
        unfolding levelsCounter_def
        by simp
      hence "(levelsCounter a) = (butlast (levelsCounter p)) @ ([last (levelsCounter p)] @ (levelsCounter_aux (tl s) [1]))  
        (last (levelsCounter p)) <= hd ([last (levelsCounter p)] @ (levelsCounter_aux (tl s) [1]))"
        unfolding levelsCounter_def
        using levelsCounter_auxNotEmpty[of "p"]
        by auto
      thus ?thesis
        by auto
    next
      case False
      from p @ s = a have "levelsCounter a = levelsCounter (p @ s)"
        by simp
      also
      have " = levelsCounter_aux s (levelsCounter_aux p [0])"
        unfolding levelsCounter_def
        by (simp add: levelsCounter_auxSuffixContinues)
      also
      have " = levelsCounter_aux (tl s) ((butlast (levelsCounter_aux p [0])) @ [Suc (last (levelsCounter_aux p [0]))])"
      proof-
        from s  [] have "s = hd s # tl s"
          by simp
        then have "levelsCounter_aux s (levelsCounter_aux p [0]) = levelsCounter_aux (hd s # tl s) (levelsCounter_aux p [0])"
          by simp
        with ~marked (hd s) show ?thesis
          by simp
      qed
      also
      have " = butlast (levelsCounter_aux p [0]) @ (levelsCounter_aux (tl s) [Suc (last (levelsCounter_aux p [0]))])"
        by (simp add: levelsCounter_aux_startIrellevant)
      finally 
      have "levelsCounter a = butlast (levelsCounter_aux p [0]) @ (levelsCounter_aux (tl s) [Suc (last (levelsCounter_aux p [0]))])"
        unfolding levelsCounter_def
        by simp
      moreover
      have "hd (levelsCounter_aux (tl s) [Suc (last (levelsCounter_aux p [0]))]) >= Suc (last (levelsCounter_aux p [0]))"
      proof-
        have "(levelsCounter_aux (tl s) [Suc (last (levelsCounter_aux p [0]))])  []"
          using levelsCounter_auxNotEmpty[of "tl s"]
          by simp
        then obtain h t where "(levelsCounter_aux (tl s) [Suc (last (levelsCounter_aux p [0]))]) = h # t"
          using neq_Nil_conv[of "(levelsCounter_aux (tl s) [Suc (last (levelsCounter_aux p [0]))])"]
          by auto
        hence "h  Suc (last (levelsCounter_aux p [0]))"
          using levelsCounter_auxIncreasesFirst[of "tl s"]
          by auto
        with (levelsCounter_aux (tl s) [Suc (last (levelsCounter_aux p [0]))]) = h # t 
        show ?thesis
          by simp
      qed
      ultimately
      have "levelsCounter a = butlast (levelsCounter p) @ (levelsCounter_aux (tl s) [Suc (last (levelsCounter_aux p [0]))])  
        last (levelsCounter p)  hd (levelsCounter_aux (tl s) [Suc (last (levelsCounter_aux p [0]))])"
        unfolding levelsCounter_def
        by simp
      thus ?thesis
        using levelsCounter_auxNotEmpty[of "tl s"]
        by auto
    qed
  qed
qed
  
lemma levelsCounterPrefixToLevel:
  assumes "p = prefixToLevel level a" "level  0" "level < currentLevel a" 
  shows "? rest . rest  []  (levelsCounter a) = (levelsCounter p) @ rest"
proof-
  from assms
  obtain s :: "'a Trail" where "p @ s = a" "s  []" "marked (hd s)"
    using isProperPrefixPrefixToLevel[of "level" "a"]
    by auto
  from p @ s = a have "levelsCounter a = levelsCounter (p @ s)"
    by simp
  also
  have " = levelsCounter_aux s (levelsCounter_aux p [0])"
    unfolding levelsCounter_def
    by (simp add: levelsCounter_auxSuffixContinues)
  also
  have " = levelsCounter_aux (tl s) ((levelsCounter_aux p [0]) @ [1])"
  proof-
    from s  [] have "s = hd s # tl s"
      by simp
    then have "levelsCounter_aux s (levelsCounter_aux p [0]) = levelsCounter_aux (hd s # tl s) (levelsCounter_aux p [0])"
      by simp
    with ‹marked (hd s) show ?thesis
      by simp
  qed
  also
  have " = levelsCounter_aux p [0] @ (levelsCounter_aux (tl s) [1])"
    by (simp add: levelsCounter_aux_startIrellevant)
  finally 
  have "levelsCounter a = levelsCounter p @ (levelsCounter_aux (tl s) [1])"
    unfolding levelsCounter_def
    by simp
  moreover
  have "levelsCounter_aux (tl s) [1]  []"
    by (simp add: levelsCounter_auxNotEmpty)
  ultimately
  show ?thesis
    by simp
qed


(*--------------------------------------------------------------------------------*)
subsection‹Prefix before last marked element›

primrec
prefixBeforeLastMarked  :: "'a Trail  'a Trail"
where
  "prefixBeforeLastMarked [] = []"
| "prefixBeforeLastMarked (h#t) =  (if (marked h)  (markedElements t) = [] then [] else (h#(prefixBeforeLastMarked t)))"

lemma prefixBeforeLastMarkedIsPrefixBeforeLastLevel:
  assumes "markedElements M  []"
  shows "prefixBeforeLastMarked M = prefixToLevel ((currentLevel M) - 1) M"
using assms
proof (induct M)
  case Nil
  thus ?case
    by simp
next
  case (Cons a M')
  thus ?case
  proof (cases "marked a")
    case True
    hence "currentLevel (a # M')  1"
      unfolding currentLevel_def
      by simp
    with True Cons show ?thesis
      using prefixToLevel_auxIncreaseAuxilaryCounter[of "0" "1" "M'" "currentLevel M' - 1"]
      unfolding prefixToLevel_def
      unfolding currentLevel_def
      by auto
  next
    case False
    with Cons show ?thesis
      unfolding prefixToLevel_def
      unfolding currentLevel_def
      by auto
  qed
qed

lemma isPrefixPrefixBeforeLastMarked:
  shows "isPrefix (prefixBeforeLastMarked M) M"
unfolding isPrefix_def
by (induct M) auto

lemma lastMarkedNotInPrefixBeforeLastMarked:
  assumes "uniq (elements M)" and "markedElements M  []"
  shows "¬ (lastMarked M)  set (elements (prefixBeforeLastMarked M))"
using assms
unfolding lastMarked_def
by (induct M) (auto split: if_split_asm simp add: markedElementsAreElements)

lemma uniqImpliesPrefixBeforeLastMarkedIsPrefixBeforeLastMarked:
  assumes "markedElements M  []" and "(lastMarked M)  set (elements M)"
  shows "prefixBeforeLastMarked M = prefixBeforeElement (lastMarked M) M"
using assms
unfolding lastMarked_def
proof (induct M)
  case Nil
  thus ?case
    by auto
next
  case (Cons a M')
  show ?case
  proof (cases "marked a  (markedElements M') = []")
    case True
    thus ?thesis
      unfolding lastMarked_def
      by auto
  next
    case False
    hence "last (markedElements (a # M')) = last (markedElements M')"
      by auto
    thus ?thesis
      using Cons
      by (auto split: if_split_asm simp add: markedElementsAreElements)
  qed
qed

lemma markedElementsAreElementsBeforeLastDecisionAndLastDecision: 
  assumes "markedElements M  []"
  shows "(markedElements M) = (markedElements (prefixBeforeLastMarked M)) @ [lastMarked M]"
using assms
unfolding lastMarked_def
by (induct M) (auto split: if_split_asm)

end

Theory SatSolverVerification

(*    Title:              SatSolverVerification/SatSolverVerification.thy
      Author:             Filip Maric
      Maintainer:         Filip Maric <filip at matf.bg.ac.yu>
*)

section‹Verification of DPLL based SAT solvers.›
theory SatSolverVerification
imports CNF Trail
begin

text‹This theory contains a number of lemmas used in verification of
different SAT solvers. Although this file does not contain any
theorems significant on their own, it is an essential part of the SAT
solver correctness proof because it contains most of the technical
details used in the proofs that follow. These lemmas serve as a basis
for partial correctness proof for pseudo-code implementation of modern
SAT solvers described in \cite{JARrad}, in terms of Hoare logic.›

(******************************************************************************)
subsection‹Literal Trail›
(******************************************************************************)
text‹LiteralTrail is a Trail consisting of literals, where decision literals are marked.›

type_synonym LiteralTrail = "Literal Trail"

abbreviation isDecision :: "('a × bool)  bool"
  where "isDecision l == marked l"

abbreviation lastDecision :: "LiteralTrail  Literal"
  where "lastDecision M == Trail.lastMarked M"

abbreviation decisions :: "LiteralTrail  Literal list"
  where "decisions M == Trail.markedElements M"

abbreviation decisionsTo :: "Literal  LiteralTrail  Literal list"
  where "decisionsTo M l == Trail.markedElementsTo M l"

abbreviation prefixBeforeLastDecision :: "LiteralTrail  LiteralTrail"
  where "prefixBeforeLastDecision M == Trail.prefixBeforeLastMarked M"

(*--------------------------------------------------------------------------*)
(*                            I N V A R I A N T S                           *)
(*--------------------------------------------------------------------------*)
(******************************************************************************)
subsection‹Invariants›
(******************************************************************************)
text‹In this section a number of conditions will be formulated and
it will be shown that these conditions are invariant after applying
different DPLL-based transition rules.›

definition
"InvariantConsistent (M::LiteralTrail) == consistent (elements M)"

definition
"InvariantUniq (M::LiteralTrail) == uniq (elements M)"

definition
"InvariantImpliedLiterals (F::Formula) (M::LiteralTrail) ==  l. l el elements M  formulaEntailsLiteral (F @ val2form (decisionsTo l M)) l"

definition
"InvariantEquivalent (F0::Formula) (F::Formula) == equivalentFormulae F0 F"

definition
"InvariantVarsM  (M::LiteralTrail) (F0::Formula) (Vbl::Variable set) == vars (elements M)  vars F0  Vbl"

definition
"InvariantVarsF (F::Formula) (F0::Formula) (Vbl::Variable set) == vars F  vars F0  Vbl"


text‹The following invariants are used in conflict analysis.›
definition
"InvariantCFalse (conflictFlag::bool) (M::LiteralTrail) (C::Clause) == conflictFlag  clauseFalse C (elements M)"

definition
"InvariantCEntailed (conflictFlag::bool) (F::Formula) (C::Clause) == conflictFlag  formulaEntailsClause F C"

definition
"InvariantReasonClauses (F::Formula) (M::LiteralTrail) == 
   literal. literal el (elements M)  ¬ literal el decisions M  
             ( clause. formulaEntailsClause F clause  isReason clause literal (elements M))"



(*----------------------------------------------------------------------*)
(*           V E R I F I C A T I O N     L E M M A S                    *)
(*----------------------------------------------------------------------*)
subsubsection‹Auxiliary lemmas›
text‹This section contains some auxiliary lemmas that additionally 
  characterize some of invariants that have been defined.›

(*-------------------------   InvariantImpliedLiterals    ---------------------*)
text‹Lemmas about @{term InvariantImpliedLiterals}.›
lemma InvariantImpliedLiteralsWeakerVariant:
  fixes M :: LiteralTrail and F :: Formula
  assumes " l. l el elements M  formulaEntailsLiteral (F @ val2form (decisionsTo l M)) l"
  shows " l. l el elements M  formulaEntailsLiteral (F @ val2form (decisions M)) l"
proof -
  { 
    fix l :: Literal
    assume "l el elements M"
    with assms 
    have "formulaEntailsLiteral (F @ val2form (decisionsTo l M)) l"
      by simp
    have "isPrefix (decisionsTo l M) (decisions M)"
      by (simp add: markedElementsToArePrefixOfMarkedElements)
    then obtain s :: Valuation 
      where "(decisionsTo l M) @ s = (decisions M)"
      using isPrefix_def [of "decisionsTo l M" "decisions M"]
      by auto
    hence "(decisions M) = (decisionsTo l M) @ s"
      by (rule sym)
    with ‹formulaEntailsLiteral (F @ val2form (decisionsTo l M)) l
    have "formulaEntailsLiteral (F @ val2form (decisions M)) l"
      using formulaEntailsLiteralAppend [of "F @ val2form (decisionsTo l M)" "l" "val2form s"]
      by (auto simp add:formulaEntailsLiteralAppend val2formAppend)
  }
  thus ?thesis
    by simp
qed

lemma InvariantImpliedLiteralsAndElementsEntailLiteralThenDecisionsEntailLiteral: 
  fixes M :: LiteralTrail and F :: Formula and literal :: Literal
  assumes "InvariantImpliedLiterals F M" and "formulaEntailsLiteral (F @ (val2form (elements M))) literal"
  shows "formulaEntailsLiteral (F @ val2form (decisions M)) literal"
proof -
  {
    fix valuation :: Valuation
    assume "model valuation (F @ val2form (decisions M))"
    hence "formulaTrue F valuation" and "formulaTrue (val2form (decisions M)) valuation" and "consistent valuation"
      by (auto simp add: formulaTrueAppend)
    {
      fix l :: Literal
      assume "l el (elements M)"
      from ‹InvariantImpliedLiterals F M
      have " l. l el (elements M)  formulaEntailsLiteral (F @ val2form (decisions M)) l"
        by (simp add: InvariantImpliedLiteralsWeakerVariant InvariantImpliedLiterals_def)
      with l el (elements M)
      have "formulaEntailsLiteral (F @ val2form (decisions M)) l"
        by simp
      with ‹model valuation (F @ val2form (decisions M))
      have "literalTrue l valuation"
        by (simp add: formulaEntailsLiteral_def)
    } 
    hence "formulaTrue (val2form (elements M)) valuation"
      by (simp add: val2formFormulaTrue)
    with ‹formulaTrue F valuation ‹consistent valuation
    have "model valuation (F @ (val2form (elements M)))"
      by (auto simp add:formulaTrueAppend)
    with ‹formulaEntailsLiteral (F @ (val2form (elements M))) literal
    have "literalTrue literal valuation"
      by (simp add: formulaEntailsLiteral_def)
  }
  thus ?thesis 
    by (simp add: formulaEntailsLiteral_def)
qed    

lemma InvariantImpliedLiteralsAndFormulaFalseThenFormulaAndDecisionsAreNotSatisfiable: 
  fixes M :: LiteralTrail and F :: Formula
  assumes "InvariantImpliedLiterals F M" and "formulaFalse F (elements M)" 
  shows "¬ satisfiable (F @ val2form (decisions M))"
proof -
  from ‹formulaFalse F (elements M)
  have "formulaFalse (F @ val2form (decisions M)) (elements M)"
    by (simp add: formulaFalseAppend)
  moreover
  from ‹InvariantImpliedLiterals F M
  have "formulaEntailsValuation (F @ val2form (decisions M)) (elements M)"
    unfolding formulaEntailsValuation_def
    unfolding InvariantImpliedLiterals_def
    using InvariantImpliedLiteralsWeakerVariant[of "M" "F"]
    by simp
  ultimately
  show ?thesis
    using formulaFalseInEntailedValuationIsUnsatisfiable [of "F @ val2form (decisions M)" "elements M"]
    by simp
qed

lemma InvariantImpliedLiteralsHoldsForPrefix:
  fixes M :: LiteralTrail and prefix :: LiteralTrail and F :: Formula
  assumes "InvariantImpliedLiterals F M"  and "isPrefix prefix M" 
  shows "InvariantImpliedLiterals F prefix"
proof -
  {
    fix l :: Literal
    assume *: "l el elements prefix"

    from * ‹isPrefix prefix M
    have "l el elements M"
      unfolding isPrefix_def
      by auto

    from * and ‹isPrefix prefix M
    have "decisionsTo l prefix = decisionsTo l M"
      using markedElementsToPrefixElement [of "prefix" "M" "l"]
      by simp

    from ‹InvariantImpliedLiterals F M and l el elements M
    have "formulaEntailsLiteral (F @ val2form (decisionsTo l M)) l"
      by (simp add:InvariantImpliedLiterals_def)
    with ‹decisionsTo l prefix = decisionsTo l M
    have "formulaEntailsLiteral (F @ val2form (decisionsTo l prefix)) l"
      by simp
  } thus ?thesis
    by (auto simp add: InvariantImpliedLiterals_def)
qed


(*-------------------------   InvariantReasonClauses    ---------------------*)
text‹Lemmas about @{term InvariantReasonClauses}.›
lemma InvariantReasonClausesHoldsForPrefix:
  fixes F::Formula and M::LiteralTrail and p::LiteralTrail
  assumes "InvariantReasonClauses F M" and "InvariantUniq M"  and
  "isPrefix p M" 
  shows "InvariantReasonClauses F p"
proof-
  from ‹InvariantReasonClauses F M
  have *: " literal. literal el elements M  ¬ literal el decisions M  
                    ( clause. formulaEntailsClause F clause  isReason clause literal (elements M))"
    unfolding InvariantReasonClauses_def 
    by simp
  from ‹InvariantUniq M
  have "uniq (elements M)"
    unfolding InvariantUniq_def 
    by simp
  {
    fix literal::Literal
    assume "literal el elements p" and "¬ literal el decisions p"
      from ‹isPrefix p M literal el (elements p)
      have "literal el (elements M)"
        by (auto simp add: isPrefix_def)
      moreover
      from ‹isPrefix p M literal el (elements p) ¬ literal el (decisions p) ‹uniq (elements M)
      have "¬ literal el decisions M"
        using markedElementsTrailMemPrefixAreMarkedElementsPrefix [of "M" "p" "literal"]
        by auto
      ultimately
      obtain clause::Clause where
        "formulaEntailsClause F clause" "isReason clause literal (elements M)"
        using *
        by auto
      with literal el elements p ¬  literal el decisions p ‹isPrefix p M
      have "isReason clause literal (elements p)"
        using isReasonHoldsInPrefix[of "literal" "elements p" "elements M" "clause"]
        by (simp add:isPrefixElements)
      with ‹formulaEntailsClause F clause
      have " clause. formulaEntailsClause F clause  isReason clause literal (elements p)"
        by auto
  }
  thus ?thesis
    unfolding InvariantReasonClauses_def
    by auto
qed

lemma InvariantReasonClausesHoldsForPrefixElements:
  fixes F::Formula and M::LiteralTrail and p::LiteralTrail
  assumes "InvariantReasonClauses F p" and
  "isPrefix p M" and
  "literal el (elements p)" and "¬ literal el decisions M"
  shows " clause. formulaEntailsClause F clause  isReason clause literal (elements M)"
proof -
  from ‹isPrefix p M ¬ literal el (decisions M)
  have "¬ literal el (decisions p)"
    using markedElementsPrefixAreMarkedElementsTrail[of "p" "M" "literal"]
    by auto

  from ‹InvariantReasonClauses F p literal el (elements p) ¬ literal el (decisions p) obtain clause :: Clause
    where "formulaEntailsClause F clause" "isReason clause literal (elements p)"
    unfolding InvariantReasonClauses_def
    by auto
  with ‹isPrefix p M
  have "isReason clause literal (elements M)"
    using isReasonAppend [of "clause" "literal" "elements p"]
    by (auto simp add: isPrefix_def)
  with ‹formulaEntailsClause F clause
  show ?thesis
    by auto
qed

(*----------------------------------------------------------------------*)
(*           V E R I F I C A T I O N     L E M M A S                    *)
(*----------------------------------------------------------------------*)
subsubsection‹Transition rules preserve invariants›

text‹In this section it will be proved that the different DPLL-based
transition rules preserves given invariants. Rules are implicitly given
in their most general form. Explicit definition of transition rules will be
done in theories that describe specific solvers.›

(************************************************************************)
(*                       A P P L Y    D E C I D E                       *)
(************************************************************************)
text‹$Decide$ transition rule.›
lemma InvariantUniqAfterDecide: 
  fixes M :: LiteralTrail and literal :: Literal and M' :: LiteralTrail
  assumes "InvariantUniq M" and 
  "var literal  vars (elements M)" and
  "M' = M @ [(literal, True)]"
  shows "InvariantUniq M'"
proof -
  from ‹InvariantUniq M
  have "uniq (elements M)"
    unfolding InvariantUniq_def 
    .
  {
    assume "¬ uniq (elements M')"
    with ‹uniq (elements M) M' = M @ [(literal, True)]
    have "literal el (elements M)"
      using uniqButlastNotUniqListImpliesLastMemButlast [of "elements M'"]
      by auto
    hence "var literal  vars (elements M)"
      using valuationContainsItsLiteralsVariable [of "literal" "elements M"]
      by simp
    with ‹var literal  vars (elements M)
    have "False"
      by simp
  }
  thus ?thesis
    unfolding InvariantUniq_def
    by auto
qed

lemma InvariantImpliedLiteralsAfterDecide: 
  fixes F :: Formula and M :: LiteralTrail and literal :: Literal and M' :: LiteralTrail
  assumes "InvariantImpliedLiterals F M" and
  "var literal  vars (elements M)" and
  "M' = M @ [(literal, True)]"
  shows "InvariantImpliedLiterals F M'"
proof -
  {
    fix l :: Literal
    assume "l el elements M'"
    have "formulaEntailsLiteral (F @ val2form (decisionsTo l M')) l"
    proof (cases "l el elements M")
      case True
      with M' = M @ [(literal, True)]
      have "decisionsTo l M' = decisionsTo l M"
        by (simp add: markedElementsToAppend)
      with ‹InvariantImpliedLiterals F M l el elements M
      show ?thesis
        by (simp add: InvariantImpliedLiterals_def)
    next
      case False
      with l el elements M' and M' = M @ [(literal, True)]
      have "l = literal"
        by (auto split: if_split_asm)
      have "clauseEntailsLiteral [literal] literal" 
        by (simp add: clauseEntailsLiteral_def)
      moreover
      have "[literal] el (F @ val2form (decisions M) @ [[literal]])"
        by simp
      moreover
      {
        have "isDecision (last (M @ [(literal, True)]))"
          by simp
        moreover
        from ‹var literal  vars (elements M)
        have "¬ literal el (elements M)"
          using valuationContainsItsLiteralsVariable[of "literal" "elements M"]
          by auto
        ultimately
        have "decisionsTo literal (M @ [(literal, True)])  = ((decisions M) @ [literal])"
          using lastTrailElementMarkedImpliesMarkedElementsToLastElementAreAllMarkedElements [of "M @ [(literal, True)]"]
          by (simp add:markedElementsAppend)
      }
      ultimately
      show ?thesis
         using M' = M @ [(literal, True)] l = literal 
           clauseEntailsLiteralThenFormulaEntailsLiteral [of "[literal]" "F @ val2form (decisions M) @ [[literal]]" "literal"] 
         by (simp add:val2formAppend)
    qed
  }
  thus ?thesis
    by (simp add:InvariantImpliedLiterals_def)
qed

lemma InvariantVarsMAfterDecide: 
  fixes F :: Formula and F0 :: Formula and M :: LiteralTrail and literal :: Literal and M' :: LiteralTrail
  assumes "InvariantVarsM M F0 Vbl" and 
  "var literal  Vbl" and 
  "M' = M @ [(literal, True)]"
  shows "InvariantVarsM M' F0 Vbl"
proof -
  from ‹InvariantVarsM M F0 Vbl
  have "vars (elements M)  vars F0  Vbl"
    by (simp only:InvariantVarsM_def)
  from M' = M @ [(literal, True)]
  have "vars (elements M') = vars (elements (M @ [(literal, True)]))"
    by simp
  also have "... = vars (elements M @ [literal])"
    by simp
  also have "... = vars (elements M)   vars [literal]"
    using varsAppendClauses [of "elements M" "[literal]"]
    by simp
  finally
  show ?thesis
    using ‹vars (elements M)  (vars F0)  Vbl ‹var literal  Vbl
    unfolding InvariantVarsM_def
    by auto
qed

lemma InvariantConsistentAfterDecide: 
  fixes M :: LiteralTrail and literal :: Literal and M' :: LiteralTrail
  assumes "InvariantConsistent M" and 
  "var literal  vars (elements M)" and
  "M' = M @ [(literal, True)]"
  shows "InvariantConsistent M'"
proof -
  from ‹InvariantConsistent M
  have "consistent (elements M)"
    unfolding InvariantConsistent_def 
    .
  {
    assume "inconsistent (elements M')"
    with M' = M @ [(literal, True)]
    have "inconsistent (elements M)  inconsistent [literal]  ( l. literalTrue l (elements M)  literalFalse l [literal])"
      using inconsistentAppend [of "elements M" "[literal]"]
      by simp
    with ‹consistent (elements M) obtain l :: Literal 
      where "literalTrue l (elements M)" and "literalFalse l [literal]"
      by auto
    hence "(opposite l) = literal"
      by auto
    hence "var literal = var l"
      by auto
    with ‹literalTrue l (elements M)
    have "var l  vars (elements M)"
      using valuationContainsItsLiteralsVariable [of "l" "elements M"]
      by simp
    with ‹var literal = var l ‹var literal  vars (elements M)
    have "False"
      by simp
  }
  thus ?thesis
    unfolding InvariantConsistent_def
    by auto
qed

lemma InvariantReasonClausesAfterDecide:
  fixes F :: Formula and M :: LiteralTrail and M' :: LiteralTrail
  assumes "InvariantReasonClauses F M" and "InvariantUniq M" and
  "M' = M @ [(literal, True)]"
  shows "InvariantReasonClauses F M'"
proof -
  {
    fix literal' :: Literal
    assume "literal' el elements M'" and "¬ literal' el decisions M'"
    
    have " clause. formulaEntailsClause F clause  isReason clause literal' (elements M')"
    proof (cases "literal' el elements M")
      case True
      with assms ¬ literal' el decisions M' obtain clause::Clause
        where "formulaEntailsClause F clause  isReason clause literal' (elements M')"
        using InvariantReasonClausesHoldsForPrefixElements [of "F" "M" "M'" "literal'"]
        by (auto simp add:isPrefix_def)
      thus ?thesis
        by auto
    next
      case False
      with M' = M @ [(literal, True)] literal' el elements M'
      have "literal = literal'"
        by (simp split: if_split_asm)
      with M' = M @ [(literal, True)] 
      have "literal' el decisions M'"
        using markedElementIsMarkedTrue[of "literal" "M'"]
        by simp
      with ¬ literal' el decisions M'
      have "False"
        by simp
      thus ?thesis
        by simp
    qed
  }
  thus ?thesis
    unfolding InvariantReasonClauses_def
    by auto
qed

lemma InvariantCFalseAfterDecide:
  fixes conflictFlag::bool and M::LiteralTrail and C::Clause
  assumes "InvariantCFalse conflictFlag M C" and "M' = M @ [(literal, True)]"
  shows "InvariantCFalse conflictFlag M' C"
  unfolding InvariantCFalse_def
proof
  assume "conflictFlag"
  show "clauseFalse C (elements M')"
  proof -
    from ‹InvariantCFalse conflictFlag M C
    have "conflictFlag  clauseFalse C (elements M)"
      unfolding InvariantCFalse_def 
      .
    with conflictFlag
    have "clauseFalse C (elements M)"
      by simp
    with M' = M @ [(literal, True)]
    show ?thesis
      by (simp add:clauseFalseAppendValuation)
  qed
qed

(************************************************************************)
(*             A P P L Y    U N I T   P R O P A G A T E                 *)
(************************************************************************)
text‹$UnitPropagate$ transition rule.›

lemma InvariantImpliedLiteralsHoldsForUnitLiteral:
  fixes M :: LiteralTrail and F :: Formula and uClause :: Clause and uLiteral :: Literal
  assumes "InvariantImpliedLiterals F M" and
  "formulaEntailsClause F uClause" and "isUnitClause uClause uLiteral (elements M)" and
  "M' = M @ [(uLiteral, False)]"
  shows "formulaEntailsLiteral (F @ val2form (decisionsTo uLiteral M')) uLiteral"
proof-
  have "decisionsTo uLiteral M' = decisions M"
  proof -
    from ‹isUnitClause uClause uLiteral (elements M)
    have "¬ uLiteral el (elements M)"
      by (simp add: isUnitClause_def)
    with M' = M @ [(uLiteral, False)]
    show ?thesis
      using markedElementsToAppend[of "uLiteral" "M" "[(uLiteral, False)]"]
      unfolding markedElementsTo_def
      by simp
  qed
  moreover
  from ‹formulaEntailsClause F uClause ‹isUnitClause uClause uLiteral (elements M) 
  have "formulaEntailsLiteral (F @ val2form (elements M)) uLiteral"
    using unitLiteralIsEntailed [of "uClause" "uLiteral" "elements M" "F"]
    by simp
  with ‹InvariantImpliedLiterals F M
  have "formulaEntailsLiteral (F @ val2form (decisions M)) uLiteral"
    by (simp add: InvariantImpliedLiteralsAndElementsEntailLiteralThenDecisionsEntailLiteral)
  ultimately
  show ?thesis
    by simp
qed

lemma InvariantImpliedLiteralsAfterUnitPropagate:
  fixes M :: LiteralTrail and F :: Formula and uClause :: Clause and uLiteral :: Literal
  assumes "InvariantImpliedLiterals F M" and
  "formulaEntailsClause F uClause" and "isUnitClause uClause uLiteral (elements M)" and
  "M' = M @ [(uLiteral, False)]"
  shows "InvariantImpliedLiterals F M'"
proof -
  {
    fix l :: Literal
    assume "l el (elements M')"
    have "formulaEntailsLiteral (F @ val2form (decisionsTo l M')) l"
    proof (cases "l el elements M")
      case True
      with ‹InvariantImpliedLiterals F M
      have "formulaEntailsLiteral (F @ val2form (decisionsTo l M)) l"
        by (simp add:InvariantImpliedLiterals_def)
      moreover
      from M' = M @ [(uLiteral, False)]
      have "(isPrefix M M')"
        by (simp add:isPrefix_def)
      with True
      have "decisionsTo l M' = decisionsTo l M"
        by (simp add: markedElementsToPrefixElement)
      ultimately
      show ?thesis
        by simp
    next
      case False
      with l el (elements M') M' = M @ [(uLiteral, False)]
      have "l = uLiteral"
        by (auto split: if_split_asm)
      moreover
      from assms
      have "formulaEntailsLiteral (F @ val2form (decisionsTo uLiteral M')) uLiteral"
        using InvariantImpliedLiteralsHoldsForUnitLiteral [of "F" "M" "uClause" "uLiteral" "M'"]
        by simp
      ultimately
      show ?thesis
        by simp
    qed
  }
  thus ?thesis
    by (simp add:InvariantImpliedLiterals_def)
qed

lemma InvariantVarsMAfterUnitPropagate: 
  fixes F :: Formula and F0 :: Formula and M :: LiteralTrail and uClause :: Clause and uLiteral :: Literal and M' :: LiteralTrail
  assumes "InvariantVarsM M F0 Vbl" and
  "var uLiteral  vars F0  Vbl" and
  "M' = M @ [(uLiteral, False)]"
  shows "InvariantVarsM M' F0 Vbl"
proof -
  from ‹InvariantVarsM M F0 Vbl
  have "vars (elements M)   vars F0  Vbl"
    unfolding InvariantVarsM_def 
    .
  thus ?thesis
    unfolding InvariantVarsM_def
    using ‹var uLiteral  vars F0  Vbl
    using M' = M @ [(uLiteral, False)]
      varsAppendClauses [of "elements M" "[uLiteral]"]
    by auto
qed

lemma InvariantConsistentAfterUnitPropagate:
  fixes M :: LiteralTrail and F :: Formula and M' :: LiteralTrail and uClause :: Clause and uLiteral :: Literal
  assumes "InvariantConsistent M" and
  "isUnitClause uClause uLiteral (elements M)" and
  "M' = M @ [(uLiteral, False)]"
  shows "InvariantConsistent M'"
proof -
  from ‹InvariantConsistent M
  have "consistent (elements M)"
    unfolding InvariantConsistent_def 
    .
  from ‹isUnitClause uClause uLiteral (elements M)
  have "¬ literalFalse uLiteral (elements M)"
    unfolding isUnitClause_def
    by simp
  {
    assume "inconsistent (elements M')"
    with M' = M @ [(uLiteral, False)]
    have "inconsistent (elements M)  inconsistent [unitLiteral]  ( l. literalTrue l (elements M)  literalFalse l [uLiteral])"
      using inconsistentAppend [of "elements M" "[uLiteral]"]
      by simp
    with ‹consistent (elements M) obtain literal::Literal
      where "literalTrue literal (elements M)" and "literalFalse literal [uLiteral]"
      by auto
    hence "literal = opposite uLiteral"
      by auto
    with ‹literalTrue literal (elements M) ¬ literalFalse uLiteral (elements M)
    have False
      by simp
  } thus ?thesis
    unfolding InvariantConsistent_def
    by auto
qed

lemma InvariantUniqAfterUnitPropagate:
  fixes M :: LiteralTrail and F :: Formula and M' :: LiteralTrail and uClause :: Clause and uLiteral :: Literal
  assumes "InvariantUniq M" and
  "isUnitClause uClause uLiteral (elements M)" and
  "M' = M @ [(uLiteral, False)]"
  shows "InvariantUniq M'"
proof-
  from ‹InvariantUniq M
  have "uniq (elements M)"
    unfolding InvariantUniq_def 
    .
  moreover
  from ‹isUnitClause uClause uLiteral (elements M)
  have "¬ literalTrue uLiteral (elements M)"
    unfolding isUnitClause_def
    by simp
  ultimately
  show ?thesis
    using M' = M @ [(uLiteral, False)] uniqAppendElement[of "elements M" "uLiteral"]
    unfolding InvariantUniq_def
    by simp
qed

lemma InvariantReasonClausesAfterUnitPropagate:
  fixes M :: LiteralTrail and F :: Formula and M' :: LiteralTrail and uClause :: Clause and uLiteral :: Literal
  assumes "InvariantReasonClauses F M" and
  "formulaEntailsClause F uClause" and "isUnitClause uClause uLiteral (elements M)" and
  "M' = M @ [(uLiteral, False)]"
  shows "InvariantReasonClauses F M'"
proof -
  from ‹InvariantReasonClauses F M
  have *: "( literal. (literal el (elements M))  ¬ (literal el (decisions M))  
    ( clause. formulaEntailsClause F clause  (isReason clause literal (elements M))))"
    unfolding InvariantReasonClauses_def 
    by simp
  {
    fix literal::Literal
    assume "literal el elements M'" "¬ literal el decisions M'"
    have " clause. formulaEntailsClause F clause  isReason clause literal (elements M')" 
    proof (cases "literal el elements M")
      case True
      with assms ¬ literal el decisions M' obtain clause::Clause
        where "formulaEntailsClause F clause  isReason clause literal (elements M')"
        using InvariantReasonClausesHoldsForPrefixElements [of "F" "M" "M'" "literal"]
        by (auto simp add:isPrefix_def)
      thus ?thesis
        by auto
    next
      case False
      with literal el (elements M') M' = M @ [(uLiteral, False)]
      have "literal = uLiteral"
        by simp
      with M' = M @ [(uLiteral, False)] ‹isUnitClause uClause uLiteral (elements M) ‹formulaEntailsClause F uClause
      show ?thesis
        using isUnitClauseIsReason [of "uClause" "uLiteral" "elements M"]
        by auto
    qed 
  } thus ?thesis
    unfolding InvariantReasonClauses_def
    by simp
qed

lemma InvariantCFalseAfterUnitPropagate:
  fixes M :: LiteralTrail and F :: Formula and M' :: LiteralTrail and uClause :: Clause and uLiteral :: Literal
  assumes "InvariantCFalse conflictFlag M C" and
  "M' = M @ [(uLiteral, False)]"
  shows "InvariantCFalse conflictFlag M' C"
proof-
  from ‹InvariantCFalse conflictFlag M C 
  have *: "conflictFlag  clauseFalse C (elements M)"
    unfolding InvariantCFalse_def 
    .
  {
    assume "conflictFlag" 
    with M' = M @ [(uLiteral, False)] * 
    have "clauseFalse C (elements M')"
      by (simp add:clauseFalseAppendValuation)
  }
  thus ?thesis
    unfolding InvariantCFalse_def
    by simp
qed

(************************************************************************)
(*                   A P P L Y    B A C K T R A C K                     *)
(************************************************************************)
text‹$Backtrack$ transition rule.›
lemma InvariantImpliedLiteralsAfterBacktrack:
  fixes F::Formula and M::LiteralTrail
  assumes "InvariantImpliedLiterals F M" and "InvariantUniq M" and "InvariantConsistent M" and 
  "decisions M  []" and "formulaFalse F (elements M)"
  "M' = (prefixBeforeLastDecision M) @ [(opposite (lastDecision M), False)]"
  shows "InvariantImpliedLiterals F M'"
proof -
  have "isPrefix (prefixBeforeLastDecision M) M"
    by (simp add: isPrefixPrefixBeforeLastMarked)
  {
    fix l'::Literal
    assume "l' el (elements M')"
    let ?p = "(prefixBeforeLastDecision M)"
    let ?l = "lastDecision M"
    have "formulaEntailsLiteral (F @ val2form (decisionsTo l' M')) l'"
    proof (cases "l' el (elements ?p)")
      case True
      with ‹isPrefix ?p M
      have "l' el (elements M)"
        using prefixElementsAreTrailElements[of "?p" "M"]
        by auto

      with ‹InvariantImpliedLiterals F M 
      have "formulaEntailsLiteral (F @ val2form (decisionsTo l' M)) l'"
        unfolding InvariantImpliedLiterals_def
        by simp
      moreover
      from M' = ?p @ [(opposite ?l, False)] True ‹isPrefix ?p M
      have "(decisionsTo l' M') = (decisionsTo l' M)"
        using prefixToElementToPrefixElement[of "?p" "M" "l'"]
        unfolding markedElementsTo_def
        by (auto simp add: prefixToElementAppend)
      ultimately
      show ?thesis
        by auto
    next
      case False
      with l' el (elements M') and M' = ?p @ [(opposite ?l, False)]
      have "?l = (opposite l')"
        by (auto split: if_split_asm)
      hence "l' = (opposite ?l)"
        by simp

      from ‹InvariantUniq M and ‹markedElements M  []
      have "(decisionsTo ?l M) = (decisions M)"
        unfolding InvariantUniq_def
        using markedElementsToLastMarkedAreAllMarkedElements
        by auto
      moreover
      from ‹decisions M  [] 
      have "?l el (elements M)"
        by (simp add: lastMarkedIsMarkedElement markedElementsAreElements)
      with ‹InvariantConsistent M 
      have "¬ (opposite ?l) el (elements M)"
        unfolding InvariantConsistent_def
        by (simp add: inconsistentCharacterization)
      with ‹isPrefix ?p M
      have "¬ (opposite ?l) el (elements ?p)"
        using prefixElementsAreTrailElements[of "?p" "M"]
        by auto
      with M' = ?p @ [(opposite ?l, False)] 
      have "decisionsTo (opposite ?l) M' = decisions ?p"
        using markedElementsToAppend [of "opposite ?l" "?p" "[(opposite ?l, False)]"]
        unfolding markedElementsTo_def
        by simp
      moreover
      from ‹InvariantUniq M ‹decisions M  []
      have "¬ ?l el (elements ?p)"
        unfolding InvariantUniq_def
        using lastMarkedNotInPrefixBeforeLastMarked[of "M"]
        by simp
      hence "¬ ?l el (decisions ?p)"
        by (auto simp add: markedElementsAreElements)
      hence "(removeAll ?l (decisions ?p)) = (decisions ?p)"
        by (simp add: removeAll_id)
      hence "(removeAll ?l ((decisions ?p) @ [?l])) = (decisions ?p)"
        by simp
      from ‹decisions M  [] False l' = (opposite ?l)
      have "(decisions ?p) @ [?l] = (decisions M)"
        using markedElementsAreElementsBeforeLastDecisionAndLastDecision[of "M"]
        by simp
      with (removeAll ?l ((decisions ?p) @ [?l])) = (decisions ?p)
      have "(decisions ?p) = (removeAll ?l (decisions M))"
        by simp
      moreover
      from ‹formulaFalse F (elements M) ‹InvariantImpliedLiterals F M
      have "¬ satisfiable (F @ (val2form (decisions M)))"
        using InvariantImpliedLiteralsAndFormulaFalseThenFormulaAndDecisionsAreNotSatisfiable[of "F" "M"]
        by simp

      from ‹decisions M  [] 
      have "?l el (decisions M)"
        unfolding lastMarked_def
        by simp
      hence "[?l] el val2form (decisions M)"
        using val2FormEl[of "?l" "(decisions M)"]
        by simp
      with ¬ satisfiable (F @ (val2form (decisions M)))
      have "formulaEntailsLiteral (removeAll [?l] (F @ val2form (decisions M))) (opposite ?l)"
        using unsatisfiableFormulaWithSingleLiteralClause[of "F @ val2form (decisions M)" "lastDecision M"]
        by auto
      ultimately
      show ?thesis
        using l' = (opposite ?l)
        using formulaEntailsLiteralRemoveAllAppend[of "[?l]" "F" "val2form (removeAll ?l (decisions M))" "opposite ?l"]
        by (auto simp add: val2FormRemoveAll)
    qed
  }
  thus ?thesis
    unfolding InvariantImpliedLiterals_def
    by auto
qed

lemma InvariantConsistentAfterBacktrack:
  fixes F::Formula and M::LiteralTrail
  assumes "InvariantUniq M" and "InvariantConsistent M" and
  "decisions M  []" and 
  "M' = (prefixBeforeLastDecision M) @ [(opposite (lastDecision M), False)]"
  shows "InvariantConsistent M'"
proof-
  from ‹decisions M  [] ‹InvariantUniq M
  have "¬ lastDecision M el elements (prefixBeforeLastDecision M)" 
    unfolding InvariantUniq_def
    using lastMarkedNotInPrefixBeforeLastMarked
    by simp
  moreover
  from ‹InvariantConsistent M 
  have "consistent (elements (prefixBeforeLastDecision M))"
    unfolding InvariantConsistent_def
    using isPrefixPrefixBeforeLastMarked[of "M"]
    using isPrefixElements[of "prefixBeforeLastDecision M" "M"]
    using consistentPrefix[of "elements (prefixBeforeLastDecision M)" "elements M"]
    by simp
  ultimately 
  show ?thesis
    unfolding InvariantConsistent_def 
    using M' = (prefixBeforeLastDecision M) @ [(opposite (lastDecision M), False)]
    using inconsistentAppend[of "elements (prefixBeforeLastDecision M)" "[opposite (lastDecision M)]"]
    by (auto split: if_split_asm)
qed

lemma InvariantUniqAfterBacktrack:
  fixes F::Formula and M::LiteralTrail
  assumes "InvariantUniq M" and "InvariantConsistent M" and
  "decisions M  []" and
  "M' = (prefixBeforeLastDecision M) @ [(opposite (lastDecision M), False)]"
  shows "InvariantUniq M'"
proof-
  from ‹InvariantUniq M
  have "uniq (elements (prefixBeforeLastDecision M))"
    unfolding InvariantUniq_def
    using isPrefixPrefixBeforeLastMarked[of "M"]
    using isPrefixElements[of "prefixBeforeLastDecision M" "M"]
    using uniqListImpliesUniqPrefix
    by simp
  moreover
  from ‹decisions M  []
  have "lastDecision M el (elements M)"
    using lastMarkedIsMarkedElement[of "M"]
    using markedElementsAreElements[of "lastDecision M" "M"]
    by simp
  with ‹InvariantConsistent M
  have "¬ opposite (lastDecision M) el (elements M)"
    unfolding InvariantConsistent_def
    using inconsistentCharacterization
    by simp
  hence "¬ opposite (lastDecision M) el (elements (prefixBeforeLastDecision M))"
    using isPrefixPrefixBeforeLastMarked[of "M"]
    using isPrefixElements[of "prefixBeforeLastDecision M" "M"]
    using prefixIsSubset[of "elements (prefixBeforeLastDecision M)" "elements M"]
    by auto
  ultimately
  show ?thesis
    using 
      M' = (prefixBeforeLastDecision M) @ [(opposite (lastDecision M), False)]
      uniqAppendElement[of "elements (prefixBeforeLastDecision M)" "opposite (lastDecision M)"]
    unfolding InvariantUniq_def
    by simp
qed

lemma InvariantVarsMAfterBacktrack:
  fixes F::Formula and M::LiteralTrail
  assumes "InvariantVarsM M F0 Vbl"
  "decisions M  []" and
  "M' = (prefixBeforeLastDecision M) @ [(opposite (lastDecision M), False)]"
  shows "InvariantVarsM M' F0 Vbl"
proof-
  from ‹decisions M  []
  have "lastDecision M el (elements M)"
    using lastMarkedIsMarkedElement[of "M"]
    using markedElementsAreElements[of "lastDecision M" "M"]
    by simp
  hence "var (lastDecision M)  vars (elements M)"
    using valuationContainsItsLiteralsVariable[of "lastDecision M" "elements M"]
    by simp
  moreover
  have "vars (elements (prefixBeforeLastDecision M))  vars (elements M)"
    using isPrefixPrefixBeforeLastMarked[of "M"]
    using isPrefixElements[of "prefixBeforeLastDecision M" "M"]
    using varsPrefixValuation[of "elements (prefixBeforeLastDecision M)" "elements M"]
    by auto
  ultimately
  show ?thesis
    using assms
    using varsAppendValuation[of "elements (prefixBeforeLastDecision M)" "[opposite (lastDecision M)]"]
    unfolding InvariantVarsM_def
    by auto
qed


(************************************************************************)
(*                     A P P L Y    B A C K J U M P                     *)
(************************************************************************)
text‹$Backjump$ transition rule.›

lemma InvariantImpliedLiteralsAfterBackjump:
  fixes F::Formula and M::LiteralTrail and p::LiteralTrail and bClause::Clause and bLiteral::Literal
  assumes "InvariantImpliedLiterals F M" and
  "isPrefix p M" and "formulaEntailsClause F bClause" and "isUnitClause bClause bLiteral (elements p)" and
  "M' = p @ [(bLiteral, False)]"
  shows "InvariantImpliedLiterals F M'"
proof -
  from ‹InvariantImpliedLiterals F M ‹isPrefix p M 
  have "InvariantImpliedLiterals F p"
    using InvariantImpliedLiteralsHoldsForPrefix [of "F" "M" "p"]
    by simp

  with assms
  show ?thesis
    using InvariantImpliedLiteralsAfterUnitPropagate [of "F" "p" "bClause" "bLiteral" "M'"]
    by simp
qed

lemma InvariantVarsMAfterBackjump:
  fixes F::Formula and M::LiteralTrail and p::LiteralTrail and bClause::Clause and bLiteral::Literal
  assumes "InvariantVarsM M F0 Vbl" and
  "isPrefix p M" and "var bLiteral  vars F0  Vbl" and
  "M' = p @ [(bLiteral, False)]"
  shows "InvariantVarsM M' F0 Vbl"
proof -
  from ‹InvariantVarsM M F0 Vbl
  have "vars (elements M)  vars F0  Vbl"
    unfolding InvariantVarsM_def
    . 
  moreover
  from ‹isPrefix p M
  have "vars (elements p)  vars (elements M)"
    using varsPrefixValuation [of "elements p" "elements M"]
    by (simp add: isPrefixElements)
  ultimately
  have "vars (elements p)  vars F0  Vbl"
    by simp

  with ‹vars (elements p)  vars F0  Vbl assms
  show ?thesis
    using InvariantVarsMAfterUnitPropagate[of  "p" "F0" "Vbl" "bLiteral" "M'"]
    unfolding InvariantVarsM_def
    by simp
qed

lemma InvariantConsistentAfterBackjump:
  fixes F::Formula and M::LiteralTrail and p::LiteralTrail and bClause::Clause and bLiteral::Literal
  assumes "InvariantConsistent M" and
  "isPrefix p M" and "isUnitClause bClause bLiteral (elements p)" and
  "M' = p @ [(bLiteral, False)]"
  shows "InvariantConsistent M'"
proof-
  from ‹InvariantConsistent M
  have "consistent (elements M)"
    unfolding InvariantConsistent_def
    .
  with ‹isPrefix p M
  have "consistent (elements p)"
    using consistentPrefix [of "elements p" "elements M"]
    by (simp add: isPrefixElements)
  
  with assms
  show ?thesis
    using InvariantConsistentAfterUnitPropagate [of "p" "bClause" "bLiteral" "M'"]
    unfolding InvariantConsistent_def
    by simp
qed

lemma InvariantUniqAfterBackjump:
  fixes F::Formula and M::LiteralTrail and p::LiteralTrail and bClause::Clause and bLiteral::Literal
  assumes "InvariantUniq M" and
  "isPrefix p M"  and "isUnitClause bClause bLiteral (elements p)" and
  "M' = p @ [(bLiteral, False)]" 
  shows "InvariantUniq M'"
proof -
  from ‹InvariantUniq M
  have "uniq (elements M)"
    unfolding InvariantUniq_def
    .
  with ‹isPrefix p M
  have "uniq (elements p)"
    using uniqElementsTrailImpliesUniqElementsPrefix [of "p" "M"]
    by simp
  with assms
  show ?thesis
    using InvariantUniqAfterUnitPropagate[of "p" "bClause" "bLiteral" "M'"]
    unfolding InvariantUniq_def
    by simp
qed


lemma InvariantReasonClausesAfterBackjump:
  fixes F::Formula and M::LiteralTrail and p::LiteralTrail and bClause::Clause and bLiteral::Literal
  assumes "InvariantReasonClauses F M" and "InvariantUniq M"  and
  "isPrefix p M"  and "isUnitClause bClause bLiteral (elements p)" and "formulaEntailsClause F bClause" and
  "M' = p @ [(bLiteral, False)]"
  shows "InvariantReasonClauses F M'"
proof -
  from ‹InvariantReasonClauses F M ‹InvariantUniq M ‹isPrefix p M
  have "InvariantReasonClauses F p"
    by (rule InvariantReasonClausesHoldsForPrefix)
  with assms
  show ?thesis
    using InvariantReasonClausesAfterUnitPropagate [of "F" "p" "bClause" "bLiteral" "M'"]
    by simp
qed

(************************************************************************)
(*                       A P P L Y    L E A R N                         *)
(************************************************************************)
text‹$Learn$ transition rule.›

lemma InvariantImpliedLiteralsAfterLearn: 
  fixes F :: Formula and F' :: Formula and M :: LiteralTrail and C :: Clause
  assumes "InvariantImpliedLiterals F M" and
  "F' = F @ [C]"
  shows "InvariantImpliedLiterals F' M"
proof -
  from ‹InvariantImpliedLiterals F M 
  have *: " l. l el (elements M)  formulaEntailsLiteral (F @ val2form (decisionsTo l M)) l"
    unfolding InvariantImpliedLiterals_def
    .
  {
    fix literal :: Literal
    assume "literal el (elements M)"
    with * 
    have "formulaEntailsLiteral (F @ val2form (decisionsTo literal M)) literal"
      by simp
    hence "formulaEntailsLiteral (F @ [C] @ val2form (decisionsTo literal M)) literal"
    proof-
      have " clause::Clause. clause el (F @ val2form (decisionsTo literal M))  clause el (F @ [C] @ val2form (decisionsTo literal M))"
      proof-
        {
          fix clause :: Clause
          have "clause el (F @ val2form (decisionsTo literal M))  clause el (F @ [C] @ val2form (decisionsTo literal M))"
          proof
            assume "clause el (F @ val2form (decisionsTo literal M))"
            thus "clause el (F @ [C] @ val2form (decisionsTo literal M))"
              by auto
          qed
        } thus ?thesis
          by auto
      qed
      with ‹formulaEntailsLiteral (F @ val2form (decisionsTo literal M)) literal
      show ?thesis
        by (rule formulaEntailsLiteralSubset)
    qed
  }
  thus ?thesis
    unfolding InvariantImpliedLiterals_def
    using F' = F @ [C]
    by auto
qed

lemma InvariantReasonClausesAfterLearn:
  fixes F :: Formula and F' :: Formula and M :: LiteralTrail and C :: Clause
  assumes "InvariantReasonClauses F M" and
  "formulaEntailsClause F C" and
  "F' = F @ [C]"
  shows "InvariantReasonClauses F' M"
proof -
  {
    fix literal :: Literal
    assume "literal el elements M  ¬ literal el decisions M"
    with ‹InvariantReasonClauses F M obtain clause::Clause
      where "formulaEntailsClause F clause" "isReason clause literal (elements M)"
      unfolding InvariantReasonClauses_def
      by auto
    from ‹formulaEntailsClause F clause F' = F @ [C]
    have "formulaEntailsClause F' clause"
      by (simp add:formulaEntailsClauseAppend)
    with ‹isReason clause literal (elements M)
    have " clause. formulaEntailsClause F' clause  isReason clause literal (elements M)"
      by auto
  } thus ?thesis
    unfolding InvariantReasonClauses_def
    by simp
qed

lemma InvariantVarsFAfterLearn:
  fixes F0 :: Formula and F :: Formula and F' :: Formula and C :: Clause
  assumes "InvariantVarsF F F0 Vbl" and 
  "vars C  (vars F0)  Vbl" and
  "F' = F @ [C]"
  shows "InvariantVarsF F' F0 Vbl"
using assms
using varsAppendFormulae[of "F" "[C]"]
unfolding InvariantVarsF_def
by auto
  

lemma InvariantEquivalentAfterLearn: 
  fixes F0 :: Formula and F :: Formula and F' :: Formula and C :: Clause
  assumes "InvariantEquivalent F0 F" and 
  "formulaEntailsClause F C" and
  "F' = F @ [C]"
  shows "InvariantEquivalent F0 F'"
proof-
  from ‹InvariantEquivalent F0 F
  have "equivalentFormulae F0 F"
    unfolding InvariantEquivalent_def
    .
  with ‹formulaEntailsClause F C F' = F @ [C]
  have "equivalentFormulae F0 (F @ [C])"
    using extendEquivalentFormulaWithEntailedClause [of "F0" "F" "C"]
    by simp
  thus ?thesis
    unfolding InvariantEquivalent_def
    using F' = F @ [C]
    by simp
qed

lemma InvariantCEntailedAfterLearn:
  fixes F0 :: Formula and F :: Formula and F' :: Formula and C :: Clause
  assumes "InvariantCEntailed conflictFlag F C" and
  "F' = F @ [C]"
  shows "InvariantCEntailed conflictFlag F' C"
using assms
unfolding InvariantCEntailed_def
by (auto simp add:formulaEntailsClauseAppend)

(************************************************************************)
(*                     A P P L Y    E X P L A I N                       *)
(************************************************************************)
text‹$Explain$ transition rule.›

lemma InvariantCFalseAfterExplain: 
  fixes conflictFlag::bool and M::LiteralTrail and C::Clause and literal :: Literal
  assumes "InvariantCFalse conflictFlag M C" and
  "opposite literal el C" and "isReason reason literal (elements M)" and
  "C' = resolve C reason (opposite literal)"
  shows "InvariantCFalse conflictFlag M C'"
unfolding InvariantCFalse_def
proof
  assume "conflictFlag"
  with ‹InvariantCFalse conflictFlag M C
  have "clauseFalse C (elements M)"
    unfolding InvariantCFalse_def
    by simp
  hence "clauseFalse (removeAll (opposite literal) C) (elements M)"
    by (simp add: clauseFalseIffAllLiteralsAreFalse)
  moreover
  from ‹isReason reason literal (elements M)
  have "clauseFalse (removeAll literal reason) (elements M)"
    unfolding isReason_def
    by simp
  ultimately 
  show "clauseFalse C' (elements M)"
    using C' = resolve C reason (opposite literal)
    resolveFalseClauses [of "opposite literal" "C" "elements M" "reason"]
    by simp
qed

lemma InvariantCEntailedAfterExplain: 
  fixes conflictFlag::bool and M::LiteralTrail and C::Clause and literal :: Literal and reason :: Clause
  assumes "InvariantCEntailed conflictFlag F C" and
  "formulaEntailsClause F reason" and "C' = (resolve C reason (opposite l))"
  shows "InvariantCEntailed conflictFlag F C'"
unfolding InvariantCEntailed_def
proof
  assume "conflictFlag"
  with ‹InvariantCEntailed conflictFlag F C
  have "formulaEntailsClause F C"
    unfolding InvariantCEntailed_def
    by simp
  with ‹formulaEntailsClause F reason
  show "formulaEntailsClause F C'"
    using C' = (resolve C reason (opposite l))
    by (simp add:formulaEntailsResolvent)
qed


(************************************************************************)
(*                     A P P L Y    C O N F L I C T                     *)
(************************************************************************)
text‹$Conflict$ transition rule.›

lemma invariantCFalseAfterConflict:
  fixes conflictFlag::bool and conflictFlag'::bool and M::LiteralTrail and F :: Formula and clause :: Clause and C' :: Clause
  assumes "conflictFlag = False" and
  "formulaFalse F (elements M)" and "clause el F" "clauseFalse clause (elements M)" and
  "C' = clause" and "conflictFlag' = True"
  shows "InvariantCFalse conflictFlag' M C'"
unfolding InvariantCFalse_def
proof
  from conflictFlag' = True›
  show "clauseFalse C' (elements M)"
    using ‹clauseFalse clause (elements M) C' = clause
    by simp
qed
  
lemma invariantCEntailedAfterConflict:
  fixes conflictFlag::bool and conflictFlag'::bool and M::LiteralTrail and F :: Formula and clause :: Clause and C' :: Clause
  assumes "conflictFlag = False" and
  "formulaFalse F (elements M)" and "clause el F" and "clauseFalse clause (elements M)" and
  "C' = clause" and "conflictFlag' = True"
  shows "InvariantCEntailed conflictFlag' F C'"
unfolding InvariantCEntailed_def
proof
  from conflictFlag' = True›
  show "formulaEntailsClause F C'"
    using clause el F C' = clause
    by (simp add:formulaEntailsItsClauses)
qed


(************************************************************************)
(*                   U N S A T     R E P O R T                          *)
(************************************************************************)
text‹UNSAT report›

lemma unsatReport: 
  fixes F :: Formula and M :: LiteralTrail and F0 :: Formula
  assumes "InvariantImpliedLiterals F M" and "InvariantEquivalent F0 F" and
  "decisions M = []" and "formulaFalse F (elements M)"
  shows "¬ satisfiable F0"
proof-
  have "formulaEntailsValuation F (elements M)"
  proof-
    {
      fix literal::Literal
      assume "literal el (elements M)"
      from ‹decisions M = []
      have "decisionsTo literal M = []"
        by (simp add:markedElementsEmptyImpliesMarkedElementsToEmpty)
      with literal el (elements M) ‹InvariantImpliedLiterals F M
      have "formulaEntailsLiteral F literal"
        unfolding InvariantImpliedLiterals_def
        by auto
    }
    thus ?thesis
      unfolding formulaEntailsValuation_def
      by simp
  qed
  with ‹formulaFalse F (elements M)
  have "¬ satisfiable F"
    by (simp add:formulaFalseInEntailedValuationIsUnsatisfiable)
  with ‹InvariantEquivalent F0 F
  show ?thesis
    unfolding InvariantEquivalent_def
    by (simp add:satisfiableEquivalent)
qed

lemma unsatReportExtensiveExplain:
  fixes F :: Formula and M :: LiteralTrail and F0 :: Formula and C :: Clause and conflictFlag :: bool
  assumes "InvariantEquivalent F0 F" and "InvariantCEntailed conflictFlag F C" and
  "conflictFlag" and "C = []"
  shows "¬ satisfiable F0"
proof-
  from conflictFlag ‹InvariantCEntailed conflictFlag F C
  have "formulaEntailsClause F C"
    unfolding InvariantCEntailed_def
    by simp
  with C=[]
  have "¬ satisfiable F"
    by (simp add:formulaUnsatIffImpliesEmptyClause)
  with ‹InvariantEquivalent F0 F
  show ?thesis
    unfolding InvariantEquivalent_def
    by (simp add:satisfiableEquivalent)
qed

(************************************************************************)
(*                       S A T     R E P O R T                          *)
(************************************************************************)
text‹SAT Report›

lemma satReport:
  fixes F0 :: Formula and F :: Formula and M::LiteralTrail
  assumes "vars F0  Vbl" and "InvariantVarsF F F0 Vbl" and "InvariantConsistent M" and "InvariantEquivalent F0 F" and
  "¬ formulaFalse F (elements M)" and "vars (elements M)  Vbl"
  shows "model (elements M) F0"
proof-
  from ‹InvariantConsistent M
  have "consistent (elements M)"
    unfolding InvariantConsistent_def
    .
  moreover
  from ‹InvariantVarsF F F0 Vbl 
  have "vars F  vars F0  Vbl"
    unfolding InvariantVarsF_def
    .
  with ‹vars F0  Vbl 
  have "vars F  Vbl"
    by auto
  with ‹vars (elements M)  Vbl
  have "vars F  vars (elements M)"
    by simp
  hence "formulaTrue F (elements M)  formulaFalse F (elements M)"
    by (simp add:totalValuationForFormulaDefinesItsValue)
  with ¬ formulaFalse F (elements M)
  have "formulaTrue F (elements M)"
    by simp
  ultimately
  have "model (elements M) F"
    by simp
  with ‹InvariantEquivalent F0 F
  show ?thesis
    unfolding InvariantEquivalent_def
    unfolding equivalentFormulae_def
    by auto
qed


(******************************************************************************)
subsection‹Different characterizations of backjumping›
(******************************************************************************)
text‹In this section, different characterization of applicability of
backjumping will be given.›

text‹The clause satisfies the @{term "Unique Implication Point (UIP)"} condition
  if the level of all its literals is stricly lower then the level of its last asserted literal›
definition
"isUIP l c M ==
  isLastAssertedLiteral (opposite l) (oppositeLiteralList c)(elements M)   
  ( l'. l' el c  l'  l  elementLevel (opposite l') M < elementLevel (opposite l) M)"

text@{term "Backjump level"} is a nonegative integer such that it is stricly 
  lower than the level of the last asserted literal of a clause, and greater or 
  equal then levels of all its other literals.›
definition
"isBackjumpLevel level l c M == 
  isLastAssertedLiteral (opposite l) (oppositeLiteralList c)(elements M)   
  0  level  level < elementLevel (opposite l) M 
  ( l'. l' el c  l'  l  elementLevel (opposite l') M  level)"

lemma lastAssertedLiteralHasHighestElementLevel: 
  fixes literal :: Literal and clause :: Clause and M :: LiteralTrail
  assumes "isLastAssertedLiteral literal clause (elements M)" and "uniq (elements M)"
  shows " l'. l' el clause  l' el elements M  elementLevel l' M <= elementLevel literal M"
proof -
  {
    fix l' :: Literal
    assume "l' el clause" "l' el elements M"
    hence "elementLevel l' M <= elementLevel literal M"
    proof (cases "l' = literal")
      case True
      thus ?thesis
        by simp
    next
      case False
      from ‹isLastAssertedLiteral literal clause (elements M) 
      have "literalTrue literal (elements M)" 
        " l. l el clause  l  literal  ¬  precedes literal l (elements M)"
        by (auto simp add:isLastAssertedLiteral_def)
      with l' el clause False 
      have "¬ precedes literal l' (elements M)"
        by simp
      with False l' el (elements M) ‹literalTrue literal (elements M)
      have "precedes l' literal (elements M)"
        using precedesTotalOrder [of "l'"  "elements M" "literal"]
        by simp
      with ‹uniq (elements M)
      show ?thesis
        using elementLevelPrecedesLeq [of "l'" "literal" "M"]
        by auto
    qed
  }
  thus ?thesis 
    by simp
qed

text‹When backjump clause contains only a single literal, then the backjump level is 0.›
(* additional assumption: (elementLevel l M) > 0 *)
lemma backjumpLevelZero:
  fixes M :: LiteralTrail and C :: Clause and l :: Literal
  assumes 
  "isLastAssertedLiteral (opposite l) (oppositeLiteralList C) (elements M)" and
  "elementLevel (opposite l) M > 0" and
  "set C = {l}"
  shows
  "isBackjumpLevel 0 l C M"
proof-
  have " l'. l' el C  l'  l  elementLevel (opposite l') M  0"
  proof-
    {
      fix l'::Literal
      assume "l' el C  l'  l"
      hence "False"
        using ‹set C = {l}
        by auto
    } thus ?thesis
      by auto
  qed
  with ‹elementLevel (opposite l) M > 0
    ‹isLastAssertedLiteral (opposite l) (oppositeLiteralList C) (elements M)
  show ?thesis
    unfolding isBackjumpLevel_def
    by auto
qed

text‹When backjump clause contains more than one literal, then the level of the 
  second last asserted literal can be taken as a backjump level.›
lemma backjumpLevelLastLast:
  fixes M :: LiteralTrail and C :: Clause and l :: Literal
  assumes 
  "isUIP l C M" and
  "uniq (elements M)" and
  "clauseFalse C (elements M)" and
  "isLastAssertedLiteral (opposite ll) (removeAll (opposite l) (oppositeLiteralList C)) (elements M)"
  shows
  "isBackjumpLevel (elementLevel (opposite ll) M) l C M"
proof-
  from ‹isUIP l C M 
  have "isLastAssertedLiteral (opposite l) (oppositeLiteralList C) (elements M)"
    unfolding isUIP_def
    by simp

  from ‹isLastAssertedLiteral (opposite ll) (removeAll (opposite l) (oppositeLiteralList C)) (elements M)
  have "literalTrue (opposite ll) (elements M)" "(opposite ll) el (removeAll (opposite l) (oppositeLiteralList C))"
    unfolding isLastAssertedLiteral_def
    by auto

  have " l'. l' el (oppositeLiteralList C)  literalTrue l' (elements M)"
  proof-
    {
      fix l'::Literal
      assume "l' el oppositeLiteralList C"
      hence "opposite l' el C"
        using literalElListIffOppositeLiteralElOppositeLiteralList[of "opposite l'" "C"]
        by simp
      with ‹clauseFalse C (elements M)
      have "literalTrue l' (elements M)"
        by (auto simp add: clauseFalseIffAllLiteralsAreFalse)
    }
    thus ?thesis
      by simp
  qed

  have " l'. l' el C  l'  l   
    elementLevel (opposite l') M <= elementLevel (opposite ll) M"
  proof-
    {
      fix l' :: Literal
      assume "l' el C  l'  l"
      hence "(opposite l') el (oppositeLiteralList C)" "opposite l'  opposite l"
        using literalElListIffOppositeLiteralElOppositeLiteralList
        by auto
      hence "opposite l' el (removeAll (opposite l) (oppositeLiteralList C))"
        by simp
      
      from ‹opposite l' el (oppositeLiteralList C)
         l'. l' el (oppositeLiteralList C)  literalTrue l' (elements M)
      have "literalTrue (opposite l') (elements M)"
        by simp

      with ‹opposite l' el (removeAll (opposite l) (oppositeLiteralList C)) 
        ‹isLastAssertedLiteral (opposite ll) (removeAll (opposite l) (oppositeLiteralList C)) (elements M)
        ‹uniq (elements M)
      have "elementLevel (opposite l') M <= elementLevel (opposite ll) M"
        using lastAssertedLiteralHasHighestElementLevel[of "opposite ll" "removeAll (opposite l) (oppositeLiteralList C)" "M"]
        by auto
    }
    thus ?thesis
      by simp
  qed
  moreover
  from ‹literalTrue (opposite ll) (elements M)
  have "elementLevel (opposite ll) M  0"
    by simp
  moreover 
  from (opposite ll) el (removeAll (opposite l) (oppositeLiteralList C))
  have "ll el C" and "ll  l"
    using literalElListIffOppositeLiteralElOppositeLiteralList[of "ll" "C"]
    by auto
  from ‹isUIP l C M 
  have " l'. l' el C  l'  l  elementLevel (opposite l') M < elementLevel (opposite l) M"
    unfolding isUIP_def
    by simp
  with ll el C ll  l
  have "elementLevel (opposite ll) M < elementLevel (opposite l) M"
    by simp
  ultimately
  show ?thesis
    using ‹isLastAssertedLiteral (opposite l) (oppositeLiteralList C) (elements M)
    unfolding isBackjumpLevel_def
    by simp
qed

text‹if UIP is reached then there exists correct backjump level.›
(* additional assumption: (elementLevel l M) > 0 *)
lemma isUIPExistsBackjumpLevel:
  fixes M :: LiteralTrail and c :: Clause and l :: Literal
  assumes 
  "clauseFalse c (elements M)" and
  "isUIP l c M" and
  "uniq (elements M)" and
  "elementLevel (opposite l) M > 0"
  shows
  " level. (isBackjumpLevel level l c M)"
proof-
  from ‹isUIP l c M
  have "isLastAssertedLiteral (opposite l) (oppositeLiteralList c) (elements M)"
    unfolding isUIP_def
    by simp
  show ?thesis
  proof (cases "set c = {l}")
    case True
    with ‹elementLevel (opposite l) M > 0 ‹isLastAssertedLiteral (opposite l) (oppositeLiteralList c) (elements M)
    have "isBackjumpLevel 0 l c M"
      using backjumpLevelZero[of "l" "c" "M"]
      by auto
    thus ?thesis
      by auto
  next
    case False
    have " literal. isLastAssertedLiteral literal (removeAll (opposite l) (oppositeLiteralList c)) (elements M)"
    proof-
      let ?ll = "getLastAssertedLiteral (oppositeLiteralList (removeAll l c)) (elements M)"
      
      from ‹clauseFalse c (elements M)
      have "clauseFalse (removeAll l c) (elements M)"
        by (simp add:clauseFalseRemove)
      moreover
      have "removeAll l c  []"
      proof-
        have "(set c)  {l}  set (removeAll l c)"
          by auto
        
        from ‹isLastAssertedLiteral (opposite l) (oppositeLiteralList c) (elements M) 
        have "(opposite l) el oppositeLiteralList c"
          unfolding isLastAssertedLiteral_def
          by simp
        hence "l el c"
          using literalElListIffOppositeLiteralElOppositeLiteralList[of "l" "c"]
          by simp
        hence "l  set c"
          by simp
        {
          assume "¬ ?thesis"
          hence "set (removeAll l c) = {}"
            by simp
          with (set c)  {l}  set (removeAll l c)
          have "set c  {l}"
            by simp
          with l  set c
          have "set c = {l}"
            by auto
          with False
          have "False"
            by simp
        }
        thus ?thesis
          by auto
      qed
      ultimately
      have "isLastAssertedLiteral ?ll (oppositeLiteralList (removeAll l c)) (elements M)"
        using ‹uniq (elements M)
        using getLastAssertedLiteralCharacterization [of "removeAll l c" "elements M"] 
        by simp
      hence "isLastAssertedLiteral ?ll (removeAll (opposite l) (oppositeLiteralList c)) (elements M)"
        using oppositeLiteralListRemove[of "l" "c"]
        by simp
      thus ?thesis
        by auto
    qed
    then obtain ll::Literal where "isLastAssertedLiteral ll (removeAll (opposite l) (oppositeLiteralList c)) (elements M)"
      by auto
  
    with ‹uniq (elements M) ‹clauseFalse c (elements M) ‹isUIP l c M 
    have "isBackjumpLevel (elementLevel ll M) l c M"
      using backjumpLevelLastLast[of "l" "c" "M" "opposite ll"]
      by auto
    thus ?thesis
      by auto
  qed
qed

text‹Backjump level condition ensures that the backjump clause is
unit in the prefix to backjump level.›
lemma isBackjumpLevelEnsuresIsUnitInPrefix: 
  fixes M :: LiteralTrail and conflictFlag :: bool and c :: Clause and l :: Literal
  assumes "consistent (elements M)" and "uniq (elements M)" and
  "clauseFalse c (elements M)" and "isBackjumpLevel level l c M"
  shows "isUnitClause c l (elements (prefixToLevel level M))"
proof -
  from ‹isBackjumpLevel level l c M 
  have "isLastAssertedLiteral (opposite l) (oppositeLiteralList c)(elements M)"
    "0  level"   "level < elementLevel (opposite l) M" and
    *: " l'. l' el c  l'  l  elementLevel (opposite l') M  level"
    unfolding isBackjumpLevel_def
    by auto

  from ‹isLastAssertedLiteral (opposite l)(oppositeLiteralList c) (elements M)
  have "l el c" "literalTrue (opposite l) (elements M)"
    using isLastAssertedCharacterization [of "opposite l" "c" "elements M"]
    by auto

  have "¬ literalFalse l (elements (prefixToLevel level M))"
    using level < elementLevel (opposite l) M 0 <= level ‹uniq (elements M)
    by (simp add: literalNotInEarlierLevelsThanItsLevel)
  moreover
  have "¬ literalTrue l (elements (prefixToLevel level M))" 
  proof -
    from ‹consistent (elements M) ‹literalTrue (opposite l) (elements M)
    have "¬ literalFalse (opposite l) (elements M)"
      by (auto simp add:inconsistentCharacterization)
    thus ?thesis
      using isPrefixPrefixToLevel[of "level" "M"]
        prefixElementsAreTrailElements[of "prefixToLevel level M" "M"]
      unfolding prefixToLevel_def
      by auto
  qed
  moreover
  have " l'. l' el c  l'  l  literalFalse l' (elements (prefixToLevel level M))"
  proof -
  {
    fix l' :: Literal
    assume "l' el c" "l'  l"

    from l' el c ‹clauseFalse c (elements M)
    have "literalFalse l' (elements M)"
      by (simp add:clauseFalseIffAllLiteralsAreFalse)

    have "literalFalse l' (elements (prefixToLevel level M))"
    proof -
      from l' el c l'  l
      have "elementLevel (opposite l') M <= level"
        using *
        by auto

      thus ?thesis
        using ‹literalFalse l' (elements M) 
          0 <= level
          elementLevelLtLevelImpliesMemberPrefixToLevel[of "opposite l'" "M" "level"]
        by simp
    qed
  } thus ?thesis
    by auto
  qed
  ultimately
  show ?thesis
    using l el c
    unfolding isUnitClause_def
    by simp
qed

text‹Backjump level is minimal if there is no smaller level which
       satisfies the backjump level condition. The following definition gives
       operative characterization of this notion.›
definition 
"isMinimalBackjumpLevel level l c M ==
     isBackjumpLevel level l c M  
     (if set c  {l} then 
         ( ll. ll el c  elementLevel (opposite ll) M = level) 
      else 
         level = 0
     )"

lemma isMinimalBackjumpLevelCharacterization:
assumes
"isUIP l c M"
"clauseFalse c (elements M)"
"uniq (elements M)"
shows
"isMinimalBackjumpLevel level l c M = 
  (isBackjumpLevel level l c M  
   ( level'. level' < level  ¬ isBackjumpLevel level' l c M))" (is "?lhs = ?rhs")
proof
  assume "?lhs"
  show "?rhs"
  proof (cases "set c = {l}")
    case True
    thus ?thesis
      using ?lhs
      unfolding isMinimalBackjumpLevel_def
      by auto
  next
    case False
    with ?lhs
    obtain ll 
      where "ll el c" "elementLevel (opposite ll) M = level" "isBackjumpLevel level l c M"
      unfolding isMinimalBackjumpLevel_def
      by auto
    have "l  ll"
      using ‹isMinimalBackjumpLevel level l c M
      using ‹elementLevel (opposite ll) M = level
      unfolding isMinimalBackjumpLevel_def
      unfolding isBackjumpLevel_def
      by auto
    
    show ?thesis
      using ‹isBackjumpLevel level l c M
      using ‹elementLevel (opposite ll) M = level
      using ll el c l  ll 
      unfolding isBackjumpLevel_def
      by force
  qed
next
  assume "?rhs"
  show "?lhs"
  proof (cases "set c = {l}")
    case True
    thus ?thesis
      using ?rhs
      using backjumpLevelZero[of "l" "c" "M"]
      unfolding isMinimalBackjumpLevel_def
      unfolding isBackjumpLevel_def
      by auto
  next
    case False
    from ?rhs
    have "l el c"
      unfolding isBackjumpLevel_def
      using literalElListIffOppositeLiteralElOppositeLiteralList[of "l" "c"]
      unfolding isLastAssertedLiteral_def
      by simp

    let ?oll = "getLastAssertedLiteral (removeAll (opposite l) (oppositeLiteralList c)) (elements M)"

    have "clauseFalse (removeAll l c) (elements M)"
      using ‹clauseFalse c (elements M)
      by (simp add: clauseFalseIffAllLiteralsAreFalse)
    moreover
    have "removeAll l c  []"
    proof-
      {
        assume "¬ ?thesis"
        hence "set (removeAll l c) = {}"
          by simp
        hence "set c  {l}"
          by simp
        hence False
          using ‹set c  {l}
          using l el c
          by auto
      } thus ?thesis
        by auto
    qed
    ultimately
    have "isLastAssertedLiteral ?oll (removeAll (opposite l) (oppositeLiteralList c)) (elements M)"
      using ‹uniq (elements M)
      using getLastAssertedLiteralCharacterization[of "removeAll l c" "elements M"]
      using oppositeLiteralListRemove[of "l" "c"]
      by simp
    hence  "isBackjumpLevel  (elementLevel ?oll M) l c M"
      using assms
      using backjumpLevelLastLast[of "l" "c" "M" "opposite ?oll"]
      by auto

    have "?oll el (removeAll (opposite l) (oppositeLiteralList c))"
      using ‹isLastAssertedLiteral ?oll (removeAll (opposite l) (oppositeLiteralList c)) (elements M)
      unfolding isLastAssertedLiteral_def
      by simp
    hence "?oll el (oppositeLiteralList c)" "?oll  opposite l"
      by auto
    hence "opposite ?oll el c"
      using literalElListIffOppositeLiteralElOppositeLiteralList[of "?oll" "oppositeLiteralList c"]
      by simp
    from ?oll  opposite l
    have "opposite ?oll  l"
      using oppositeSymmetry[of "?oll" "l"]
      by simp

    have "elementLevel ?oll M  level"
    proof-
      {
        assume "elementLevel ?oll M < level"
        hence "¬ isBackjumpLevel  (elementLevel ?oll M) l c M"
          using ?rhs
          by simp
        with ‹isBackjumpLevel  (elementLevel ?oll M) l c M
        have False
          by simp
      } thus ?thesis
        by force
    qed
    moreover
    from ?rhs
    have "elementLevel ?oll M  level"
      using ‹opposite ?oll el c
      using ‹opposite ?oll  l
      unfolding isBackjumpLevel_def
      by auto
    ultimately
    have "elementLevel ?oll M = level"
      by simp
    show ?thesis
      using ‹opposite ?oll el c
      using ‹elementLevel ?oll M = level
      using ?rhs
      using ‹set c  {l}
      unfolding isMinimalBackjumpLevel_def
      by (auto simp del: set_removeAll)
  qed
qed

lemma isMinimalBackjumpLevelEnsuresIsNotUnitBeforePrefix:
  fixes M :: LiteralTrail and conflictFlag :: bool and c :: Clause and l :: Literal
  assumes "consistent (elements M)" and "uniq (elements M)" and 
  "clauseFalse c (elements M)" "isMinimalBackjumpLevel level l c M" and
  "level' < level"
  shows "¬ ( l'. isUnitClause c l' (elements (prefixToLevel level' M)))"
proof-
  from ‹isMinimalBackjumpLevel level l c M
  have "isUnitClause c l (elements (prefixToLevel level M))"
    using assms
    using isBackjumpLevelEnsuresIsUnitInPrefix[of "M" "c" "level" "l"]
    unfolding isMinimalBackjumpLevel_def
    by simp
  hence "¬ literalFalse l (elements (prefixToLevel level M))"
    unfolding isUnitClause_def
    by auto
  hence "¬ literalFalse  l (elements M)  elementLevel (opposite l) M > level"
    using elementLevelLtLevelImpliesMemberPrefixToLevel[of "l" "M" "level"]
    using elementLevelLtLevelImpliesMemberPrefixToLevel[of "opposite l" "M" "level"]
    by (force)+

  have "¬ literalFalse l (elements (prefixToLevel level' M))"
  proof (cases "¬ literalFalse l (elements M)")
    case True
    thus ?thesis
      using prefixIsSubset[of "elements (prefixToLevel level' M)" "elements M"]
      using isPrefixPrefixToLevel[of "level'" "M"]
      using isPrefixElements[of "prefixToLevel level' M" "M"]
      by auto
  next
    case False
    with ¬ literalFalse l (elements M)  elementLevel (opposite l) M > level
    have "level < elementLevel (opposite l) M"
      by simp
    thus ?thesis
      using prefixToLevelElementsElementLevel[of "opposite l" "level'" "M"]
      using level' < level
      by auto
  qed

  show ?thesis
  proof (cases "set c  {l}")
    case True
    from ‹isMinimalBackjumpLevel level l c M
    obtain ll 
      where "ll el c" "elementLevel (opposite ll) M = level"
      using ‹set c  {l}
      unfolding isMinimalBackjumpLevel_def
      by auto
    hence "¬ literalFalse ll (elements (prefixToLevel level' M))"
      using literalNotInEarlierLevelsThanItsLevel[of "level'" "opposite ll" "M"]
      using level' < level
      by simp

    have "l  ll"
      using ‹isMinimalBackjumpLevel level l c M
      using ‹elementLevel (opposite ll) M = level
      unfolding isMinimalBackjumpLevel_def
      unfolding isBackjumpLevel_def
      by auto
    
    {
      assume "¬ ?thesis"
      then obtain l'
        where "isUnitClause c l' (elements (prefixToLevel level' M))"
        by auto
      have "False"
      proof (cases "l = l'")
        case True
        thus ?thesis
          using l  ll ll el c
          using ¬ literalFalse ll (elements (prefixToLevel level' M))
          using ‹isUnitClause c l' (elements (prefixToLevel level' M))
          unfolding isUnitClause_def
          by auto
      next
        case False
        have "l el c"
          using ‹isMinimalBackjumpLevel level l c M
          unfolding isMinimalBackjumpLevel_def
          unfolding isBackjumpLevel_def
          unfolding isLastAssertedLiteral_def
          using literalElListIffOppositeLiteralElOppositeLiteralList[of "l" "c"]
          by simp
        thus ?thesis
          using False
          using ¬ literalFalse l (elements (prefixToLevel level' M))
          using ‹isUnitClause c l' (elements (prefixToLevel level' M))
          unfolding isUnitClause_def
          by auto
      qed
    } thus ?thesis
      by auto
  next
    case False
    with ‹isMinimalBackjumpLevel level l c M
    have "level = 0"
      unfolding isMinimalBackjumpLevel_def
      by simp
    with level' < level
    show ?thesis
      by simp
  qed
qed

text‹If all literals in a clause are decision literals, then UIP is reached.›
lemma allDecisionsThenUIP:
  fixes M :: LiteralTrail and c:: Clause
  assumes "(uniq (elements M))" and
  " l'. l' el c  (opposite l') el (decisions M)"
  "isLastAssertedLiteral (opposite l) (oppositeLiteralList c) (elements M)"
  shows "isUIP l c M"
proof-
  from ‹isLastAssertedLiteral (opposite l) (oppositeLiteralList c) (elements M)
  have "l el c" "(opposite l) el (elements M)"
    and *: "l'. l' el (oppositeLiteralList c)  l'  opposite l  ¬ precedes (opposite l) l' (elements M)"
    unfolding isLastAssertedLiteral_def
    using "literalElListIffOppositeLiteralElOppositeLiteralList"
    by auto
  with  l'. l' el c  (opposite l') el (decisions M)
  have "(opposite l) el (decisions M)"
    by simp
  {
    fix l' :: Literal
    assume "l' el c" "l'  l"
    hence "opposite l' el (oppositeLiteralList c)" and "opposite l'  opposite l"
      using literalElListIffOppositeLiteralElOppositeLiteralList[of "l'" "c"]
      by auto
    with * 
    have "¬ precedes (opposite l) (opposite l') (elements M)"
      by simp

    from l' el c  l. l el c  (opposite l) el (decisions M)
    have "(opposite l') el (decisions M)"
      by auto
    hence "(opposite l') el (elements M)"
      by (simp add:markedElementsAreElements)

    from (opposite l) el (elements M) (opposite l') el (elements M) l'  l 
      ¬ precedes (opposite l) (opposite l') (elements M) 
    have "precedes (opposite l') (opposite l) (elements M)"
      using precedesTotalOrder [of "opposite l" "elements M" "opposite l'"]
      by simp
    with ‹uniq (elements M)
    have "elementLevel (opposite l') M <= elementLevel (opposite l) M"
      by (auto simp add:elementLevelPrecedesLeq)
    moreover
    from ‹uniq (elements M) (opposite l) el (decisions M) (opposite l') el (decisions M) l'  l
    have "elementLevel (opposite l) M  elementLevel (opposite l') M"
      using differentMarkedElementsHaveDifferentLevels[of "M" "opposite l" "opposite l'"]
      by simp
    ultimately
    have "elementLevel (opposite l') M < elementLevel (opposite l) M"
      by simp
  }
  thus ?thesis
    using ‹isLastAssertedLiteral (opposite l) (oppositeLiteralList c) (elements M)
    unfolding isUIP_def
    by simp
qed

text‹If last asserted literal of a clause is a decision literal, then UIP is reached.›
lemma lastDecisionThenUIP:
  fixes M :: LiteralTrail and c:: Clause
  assumes "(uniq (elements M))" and
  "(opposite l) el (decisions M)"
  "clauseFalse c (elements M)"
  "isLastAssertedLiteral (opposite l) (oppositeLiteralList c) (elements M)"
  shows "isUIP l c M"
proof-
  from ‹isLastAssertedLiteral (opposite l) (oppositeLiteralList c) (elements M)
  have "l el c" "(opposite l) el (elements M)"
    and *: "l'. l' el (oppositeLiteralList c)  l'  opposite l  ¬ precedes (opposite l) l' (elements M)"
    unfolding isLastAssertedLiteral_def
    using "literalElListIffOppositeLiteralElOppositeLiteralList"
    by auto
  {
    fix l' :: Literal
    assume "l' el c" "l'  l"
    hence "opposite l' el (oppositeLiteralList c)" and "opposite l'  opposite l"
      using literalElListIffOppositeLiteralElOppositeLiteralList[of "l'" "c"]
      by auto
    with * 
    have "¬ precedes (opposite l) (opposite l') (elements M)"
      by simp

    have "(opposite l') el (elements M)"
      using l' el c ‹clauseFalse c (elements M)
      by (simp add: clauseFalseIffAllLiteralsAreFalse)

    from (opposite l) el (elements M) (opposite l') el (elements M) l'  l 
      ¬ precedes (opposite l) (opposite l') (elements M) 
    have "precedes (opposite l') (opposite l) (elements M)"
      using precedesTotalOrder [of "opposite l" "elements M" "opposite l'"]
      by simp

    hence "elementLevel (opposite l') M < elementLevel (opposite l) M"
      using elementLevelPrecedesMarkedElementLt[of "M" "opposite l'" "opposite l"]
      using ‹uniq (elements M)
      using ‹opposite l el (decisions M)
      using l'  l
      by simp
  }
  thus ?thesis
    using ‹isLastAssertedLiteral (opposite l) (oppositeLiteralList c) (elements M)
    unfolding SatSolverVerification.isUIP_def
    by simp
qed

text‹If all literals in a clause are decision literals, then there
exists a backjump level for that clause.›
lemma allDecisionsThenExistsBackjumpLevel:
  fixes M :: LiteralTrail and c:: Clause
  assumes "(uniq (elements M))" and
  " l'. l' el c  (opposite l') el (decisions M)"
  "isLastAssertedLiteral (opposite l) (oppositeLiteralList c) (elements M)"
  shows " level. (isBackjumpLevel level l c M)"
proof-
  from assms 
  have "isUIP l c M"
    using allDecisionsThenUIP
    by simp
  moreover
  from ‹isLastAssertedLiteral (opposite l) (oppositeLiteralList c) (elements M)
  have "l el c"
    unfolding isLastAssertedLiteral_def
    using literalElListIffOppositeLiteralElOppositeLiteralList
    by simp
  with  l'. l' el c  (opposite l') el (decisions M)
  have "(opposite l) el (decisions M)"
    by simp
  hence "elementLevel (opposite l) M > 0"
    using ‹uniq (elements M)
      elementLevelMarkedGeq1[of "M" "opposite l"]
    by auto
  moreover
  have "clauseFalse c (elements M)"
  proof-
    {
      fix l'::Literal
      assume "l' el c"
      with  l'. l' el c  (opposite l') el (decisions M)
      have "(opposite l') el (decisions M)"
        by simp
      hence "literalFalse l' (elements M)"
        using markedElementsAreElements
        by simp
    }
    thus ?thesis
      using clauseFalseIffAllLiteralsAreFalse
      by simp
  qed
  ultimately
  show ?thesis
    using ‹uniq (elements M)
    using isUIPExistsBackjumpLevel
    by simp
qed

text‹$Explain$ is applicable to each non-decision literal in a clause.›
lemma explainApplicableToEachNonDecision:
  fixes F :: Formula and M :: LiteralTrail and conflictFlag :: bool and C :: Clause and literal :: Literal
  assumes "InvariantReasonClauses F M" and "InvariantCFalse conflictFlag M C" and
  "conflictFlag = True" and "opposite literal el C" and "¬ literal el (decisions M)"
  shows " clause. formulaEntailsClause F clause  isReason clause literal (elements M)"
proof-
  from conflictFlag = True› ‹InvariantCFalse conflictFlag M C
  have "clauseFalse C (elements M)"
    unfolding InvariantCFalse_def
    by simp
  with ‹opposite literal el C
  have "literalTrue literal (elements M)"
    by (auto simp add:clauseFalseIffAllLiteralsAreFalse)
  with ¬ literal el (decisions M) ‹InvariantReasonClauses F M
  show ?thesis
    unfolding InvariantReasonClauses_def
    by auto
qed


(**************************************************************************)
(*                          T E R M I N A T I O N                         *)
(**************************************************************************)
subsection‹Termination›
text‹In this section different ordering relations will be defined. These 
  well-founded orderings will be the basic building blocks of termination 
  orderings that will prove the termination of the SAT solving procedures›
  

text‹First we prove a simple lemma about acyclic orderings.›
lemma transIrreflexiveOrderingIsAcyclic:
  assumes "trans r" and " x. (x, x)  r"
  shows "acyclic r"
proof (rule acyclicI)
  {
    assume " x. (x, x)  r^+"
    then obtain x where "(x, x)  r^+"
      by auto
    moreover
    from ‹trans r
    have "r^+ = r"
      by (rule trancl_id)
    ultimately
    have "(x, x)  r"
      by simp
    with  x. (x, x)  r
    have False
      by simp
  }
  thus " x. (x, x)  r^+"
    by auto
qed


 
(*-----------------------------------------------------------------------*)
subsubsection‹Trail ordering›
(*-----------------------------------------------------------------------*)

text‹We define a lexicographic ordering of trails, based on the
number of literals on the different decision levels. It will be used
for transition rules that change the trail, i.e., for $Decide$,
$UnitPropagate$, $Backjump$ and $Backtrack$ transition rules.›

definition
"decisionLess = {(l1::('a*bool), l2::('a*bool)). isDecision l1  ¬ isDecision l2}"
definition
"lexLess = {(M1::'a Trail, M2::'a Trail). (M2, M1)  lexord decisionLess}"


text‹Following several lemmas will help prove that application of
some DPLL-based transition rules decreases the trail in the @{term
lexLess} ordering.›

lemma lexLessAppend:
  assumes "b  []" 
  shows "(a @ b, a)  lexLess"
proof-
  from b  []
  have " aa list. b = aa # list"
    by (simp add: neq_Nil_conv)
  then obtain aa::"'a × bool" and list :: "'a Trail"
    where "b = aa # list"
    by auto
  thus ?thesis
    unfolding lexLess_def
    unfolding lexord_def
    by simp
qed

lemma lexLessBackjump:
  assumes "p = prefixToLevel level a" and "level >= 0" and "level < currentLevel a" 
  shows "(p @ [(x, False)], a)  lexLess"
proof-
  from assms
  have " rest. prefixToLevel level a @ rest = a  rest  []  isDecision (hd rest)"
    using isProperPrefixPrefixToLevel
    by auto
  with p = prefixToLevel level a 
  obtain rest 
    where "p @ rest = a  rest  []  isDecision (hd rest)"
    by auto
  thus ?thesis
    unfolding lexLess_def
    using lexord_append_left_rightI[of "hd rest" "(x, False)" "decisionLess" "p" "tl rest" "[]"]
    unfolding decisionLess_def
    by simp
qed

lemma lexLessBacktrack:
  assumes "p = prefixBeforeLastDecision a" "decisions a  []"
  shows "(p @ [(x, False)], a)  lexLess"
using assms
using prefixBeforeLastMarkedIsPrefixBeforeLastLevel[of "a"]
using lexLessBackjump[of "p" "currentLevel a - 1" "a"]
unfolding currentLevel_def
by auto


text‹The following several lemmas prover that @{term lexLess} is
acyclic. This property will play an important role in building a
well-founded ordering based on @{term lexLess}.›
lemma transDecisionLess:
  shows "trans decisionLess"
proof-
  {
    fix x::"('a*bool)" and y::"('a*bool)" and z::"('a*bool)"
    assume "(x, y)  decisionLess" 
    hence "¬ isDecision y"
      unfolding decisionLess_def
      by simp
    moreover 
    assume "(y, z)  decisionLess"
    hence "isDecision y"
      unfolding decisionLess_def
      by simp
    ultimately
    have False
      by simp
    hence "(x, z)  decisionLess"
      by simp
  }
  thus ?thesis
    unfolding trans_def
    by blast
qed


lemma translexLess: 
  shows "trans lexLess"
proof- 
  {
    fix x :: "'a Trail" and y :: "'a Trail" and z :: "'a Trail"
    assume "(x, y)  lexLess" and "(y, z)  lexLess"
    hence "(x, z)  lexLess"
      using lexord_trans transDecisionLess
      unfolding lexLess_def
      by simp
  }
  thus ?thesis
    unfolding trans_def
    by blast
qed

lemma irreflexiveDecisionLess:
  shows "(x, x)  decisionLess"
unfolding decisionLess_def
by simp

lemma irreflexiveLexLess: 
  shows "(x, x)  lexLess"
using lexord_irreflexive[of "decisionLess" "x"] irreflexiveDecisionLess
unfolding lexLess_def
by auto

lemma acyclicLexLess:
  shows "acyclic lexLess"
proof (rule transIrreflexiveOrderingIsAcyclic)
  show "trans lexLess"
    using translexLess
    .
  show " x. (x, x)  lexLess"
    using irreflexiveLexLess
    by auto
qed

text‹The @{term lexLess} ordering is not well-founded. In order to
  get a well-founded ordering, we restrict the @{term lexLess}
  ordering to cosistent and uniq trails with fixed variable set.›
definition "lexLessRestricted (Vbl::Variable set) == {(M1, M2). 
  vars (elements M1)  Vbl  consistent (elements M1)  uniq (elements M1) 
  vars (elements M2)  Vbl  consistent (elements M2)  uniq (elements M2) 
  (M1, M2)  lexLess}"

text‹First we show that the set of those trails is finite.›
lemma finiteVarsClause:
  fixes c :: Clause
  shows "finite (vars c)"
by (induct c) auto

lemma finiteVarsFormula:
  fixes F :: Formula
  shows "finite (vars F)"
proof (induct F)
  case (Cons c F)
  thus ?case
    using finiteVarsClause[of "c"]
    by simp
qed simp

lemma finiteListDecompose:
  shows "finite {(a, b). l = a @ b}"
proof (induct l)
  case Nil
  thus ?case
    by simp
next
  case (Cons x l')
  thus ?case
  proof-
    let "?S l" = "{(a, b). l = a @ b}"
    let "?S' x l'" = "{(a', b). a' = []  b = (x # l')  
                                ( a. a' = x # a  (a, b)  (?S l'))}"
    have "?S (x # l') = ?S' x l'"
    proof
      show "?S (x # l')  ?S' x l'"
      proof
        fix k
        assume "k  ?S (x # l')"
        then obtain a and b
          where "k = (a, b)" "x # l' = a @ b"
          by auto
        then obtain a' where "a' = x # a"
          by auto
        from k = (a, b) x # l' = a @ b 
        show "k  ?S' x l'"
          using SimpleLevi[of "a" "b" "x" "l'"]
          by auto
      qed
    next
      show "?S' x l'  ?S (x # l')"
      proof
        fix k
        assume "k  ?S' x l'"
        then obtain a' and b where 
          "k = (a', b)" "a' = []  b = x # l'  ( a . a' = x # a  (a, b)  ?S l')"
          by auto
        moreover
        {
          assume "a' = []" "b = x # l'"
          with k = (a', b)
          have "k  ?S (x # l')"
            by simp
        }
        moreover
        {
          assume " a. a' = x # a  (a, b)  ?S l'"
          then obtain a where
            "a' = x # a  (a, b)  ?S l'"
            by auto
          with k = (a', b)
          have "k  ?S (x # l')"
            by auto
        }
        ultimately
        show "k  ?S (x # l')"
          by auto
      qed
    qed
    moreover
    have "?S' x l' = 
      {(a', b). a' = []  b = x # l'}  {(a', b).  a. a' = x # a  (a, b)  ?S l'}"
      by auto
    moreover
    have "finite {(a', b).  a. a' = x # a  (a, b)  ?S l'}"
    proof-
      let ?h = "λ (a, b). (x # a, b)"
      have "{(a', b).  a. a' = x # a   (a, b)  ?S l'} = ?h ` {(a, b).  l' = a @ b}"
        by auto
      thus ?thesis
        using Cons(1)
        by auto
    qed
    moreover 
    have "finite {(a', b). a' = []  b = x # l'}"
      by auto
    ultimately
    show ?thesis
      by auto
  qed
qed

lemma finiteListDecomposeSet:
  fixes L :: "'a list set"
  assumes "finite L"
  shows "finite {(a, b).  l. l  L  l = a @ b}"
proof-
  have "{(a, b).  l. l  L  l = a @ b} = ( l  L. {(a, b). l = a @ b})"
    by auto
  moreover
  have "finite ( l  L. {(a, b). l = a @ b})"
  proof (rule finite_UN_I)
    from ‹finite L
    show "finite L" 
      .
  next
    fix l
    assume "l  L"
    show "finite {(a, b). l = a @ b}"
      by (rule finiteListDecompose)
  qed
  ultimately
  show ?thesis
    by simp
qed

lemma finiteUniqAndConsistentTrailsWithGivenVariableSet: 
  fixes V :: "Variable set"
  assumes "finite V"
  shows "finite {(M::LiteralTrail). vars (elements M) = V  uniq (elements M)  consistent (elements M)}"
        (is "finite (?trails V)")
using assms
proof induct
  case empty
  thus ?case
  proof-
    have "?trails {} = {M. M = []}" (is "?lhs = ?rhs")
    proof
      show "?lhs  ?rhs"
      proof
        fix M::LiteralTrail
        assume "M  ?lhs"
        hence "M = []"
          by (induct M) auto
        thus "M  ?rhs"
          by simp
      qed
    next
      show "?rhs  ?lhs"
      proof
        fix M::LiteralTrail
        assume "M  ?rhs"
        hence "M = []"
          by simp
        thus "M  ?lhs"
          by (induct M) auto
      qed
    qed
    moreover
    have "finite {M. M = []}"
      by auto
    ultimately
    show ?thesis
      by auto
  qed
next
  case (insert v V')
  thus ?case
  proof-
    let "?trails' V'" = "{(M::LiteralTrail).  M' l d M''. 
                                M = M' @ [(l, d)] @ M'' 
                                M' @ M''  (?trails V') 
                                l  {Pos v, Neg v} 
                                d  {True, False}}"
    have "?trails (insert v V') = ?trails' V'"
      (is "?lhs = ?rhs")
    proof
      show "?lhs  ?rhs"
      proof
        fix M::LiteralTrail
        assume "M  ?lhs"
        hence "vars (elements M) = insert v V'" "uniq (elements M)" "consistent (elements M)"
          by auto
        hence "v  vars (elements M)"
          by simp
        hence " l. l el elements M  var l = v"
          by (induct M) auto
        then obtain l where "l el elements M" "var l = v"
          by auto
        hence " M' M'' d. M = M' @ [(l, d)] @ M''"
        proof (induct M)
          case (Cons m M1)
          thus ?case
          proof (cases "l = (element m)")
            case True
            then obtain d where "m = (l, d)"
              using eitherMarkedOrNotMarkedElement[of "m"]
              by auto
            hence "m # M1 = [] @ [(l, d)] @ M1"
              by simp
            then obtain M' M'' d where "m # M1 = M' @ [(l, d)] @ M''"
              ..
            thus ?thesis
              by auto
          next
            case False
            with l el elements (m # M1)
            have "l el elements M1"
              by simp
            with Cons(1) ‹var l = v
            obtain M1' M'' d where "M1 = M1' @ [(l, d)] @ M''"
              by auto
            hence "m # M1 = (m # M1') @ [(l, d)] @ M''"
              by simp
            then obtain M' M'' d where "m # M1 = M' @ [(l, d)] @ M''"
              ..
            thus ?thesis
              by auto
          qed
        qed simp
        then obtain M' M'' d where "M = M' @ [(l, d)] @ M''"
          by auto
        moreover
        from ‹var l = v
        have "l : {Pos v, Neg v}"
          by (cases l) auto
        moreover
        have *: "vars (elements (M' @ M'')) = vars (elements M')  vars (elements M'')"
          using varsAppendClauses[of "elements M'" "elements M''"]
          by simp
        from M = M' @ [(l, d)] @ M'' ‹var l = v
        have **: "vars (elements M) = (vars (elements M'))  {v}  (vars (elements M''))"
          using varsAppendClauses[of "elements M'" "elements ([(l, d)] @ M'')"]
          using varsAppendClauses[of "elements [(l, d)]" "elements M''"]
          by simp
        have ***: "vars (elements M) = vars (elements (M' @ M''))  {v}"
          using * **
          by simp
        have "M' @ M''  (?trails V')"
        proof-
          from ‹uniq (elements M) M = M' @ [(l, d)] @ M''
          have "uniq (elements (M' @ M''))"
            by (auto iff: uniqAppendIff)
          moreover
          have "consistent (elements (M' @ M''))"
          proof-
            {
              assume "¬ consistent (elements (M' @ M''))"
              then obtain l' where "literalTrue l' (elements (M' @ M''))" "literalFalse l' (elements (M' @ M''))"
                by (auto simp add:inconsistentCharacterization)
              with M = M' @ [(l, d)] @ M''
              have "literalTrue l' (elements M)" "literalFalse l' (elements M)"
                by auto
              hence "¬ consistent (elements M)"
                by (auto simp add: inconsistentCharacterization)
              with ‹consistent (elements M)
              have False
                by simp
            }
            thus ?thesis
              by auto
          qed
          moreover
          have "v  vars (elements (M' @ M''))"
          proof-
            {
              assume "v  vars (elements (M' @ M''))"
              with *
              have "v  vars (elements M')  v  vars (elements M'')"
                by simp
              moreover
              {
                assume "v  (vars (elements M'))"
                hence " l. var l = v  l el elements M'"
                  by (induct M') auto
                then obtain l' where "var l' = v" "l' el elements M'"
                  by auto
                from ‹var l = v ‹var l' = v
                have "l = l'  opposite l = l'"
                  using literalsWithSameVariableAreEqualOrOpposite[of "l" "l'"]
                  by simp
                moreover
                {
                  assume "l = l'"
                  with l' el elements M' M = M' @ [(l, d)] @ M''
                  have "¬ uniq (elements M)"
                    by (auto iff: uniqAppendIff)
                  with ‹uniq (elements M)
                  have False
                    by simp
                }
                moreover
                {
                  assume "opposite l = l'"
                  have "¬ consistent (elements M)"
                  proof-
                    from l' el elements M' M = M' @ [(l, d)] @ M''
                    have "literalTrue l' (elements M)"
                      by simp
                    moreover
                    from l' el elements M' ‹opposite l = l' M = M' @ [(l, d)] @ M''
                    have "literalFalse l' (elements M)"
                      by simp
                    ultimately
                    show ?thesis
                      by (auto simp add: inconsistentCharacterization)
                  qed
                  with ‹consistent (elements M)
                  have False
                    by simp
                }
                ultimately
                have False
                  by auto
              }
              moreover
              {
                assume "v  (vars (elements M''))"
                hence " l. var l = v  l el elements M''"
                  by (induct M'') auto
                then obtain l' where "var l' = v" "l' el (elements M'')"
                  by auto
                from ‹var l = v ‹var l' = v
                have "l = l'  opposite l = l'"
                  using literalsWithSameVariableAreEqualOrOpposite[of "l" "l'"]
                  by simp
                moreover
                {
                  assume "l = l'"
                  with l' el elements M'' M = M' @ [(l, d)] @ M''
                  have "¬ uniq (elements M)"
                    by (auto iff: uniqAppendIff)
                  with ‹uniq (elements M)
                  have False
                    by simp
                }
                moreover
                {
                  assume "opposite l = l'"
                  have "¬ consistent (elements M)"
                  proof-
                    from l' el elements M'' M = M' @ [(l, d)] @ M''
                    have "literalTrue l' (elements M)"
                      by simp
                    moreover
                    from l' el elements M'' ‹opposite l = l' M = M' @ [(l, d)] @ M''
                    have "literalFalse l' (elements M)"
                      by simp
                    ultimately
                    show ?thesis
                      by (auto simp add: inconsistentCharacterization)
                  qed
                  with ‹consistent (elements M)
                  have False
                    by simp
                }
                ultimately
                have False
                  by auto
              }
              ultimately
              have False
                by auto
            }
            thus ?thesis
              by auto
          qed
          from 
            * ** ***
            v  vars (elements (M' @ M'')) 
            ‹vars (elements M) = insert v V' 
            ¬ v  V'
          have "vars (elements (M' @ M'')) = V'"
            by (auto simp del: vars_clause_def)
          ultimately
          show ?thesis
            by simp
        qed
        ultimately
        show "M  ?rhs"
          by auto
      qed
    next
      show "?rhs  ?lhs"
      proof
        fix M :: LiteralTrail
        assume "M  ?rhs"
        then obtain M' M'' l d where 
          "M = M' @ [(l, d)] @ M''"
          "vars (elements (M' @ M'')) = V'" 
          "uniq (elements (M' @ M''))" "consistent (elements (M' @ M''))" "l  {Pos v, Neg v}"
          by auto
        from l  {Pos v, Neg v}
        have "var l = v"
          by auto
        have *: "vars (elements (M' @ M'')) = vars (elements M')  vars (elements M'')"
          using varsAppendClauses[of "elements M'" "elements M''"]
          by simp
        from ‹var l = v M = M' @ [(l, d)] @ M'' 
        have **: "vars (elements M) = vars (elements M')  {v}  vars (elements M'')"
          using varsAppendClauses[of "elements M'" "elements ([(l, d)] @ M'')"]
          using varsAppendClauses[of "elements [(l, d)]" "elements M''"]
          by simp
        from * ** ‹vars (elements (M' @ M'')) = V'
        have "vars (elements M) = insert v V'"
          by (auto simp del: vars_clause_def)
        moreover
        from *
          ‹var l = v 
          v  V' 
          ‹vars (elements (M' @ M'')) = V' 
        have "var l  vars (elements M')" "var l  vars (elements M'')"
          by auto
        from ‹var l  vars (elements M')
        have "¬ literalTrue l (elements M')" "¬ literalFalse l (elements M')"
          using valuationContainsItsLiteralsVariable[of "l" "elements M'"]
          using valuationContainsItsLiteralsVariable[of "opposite l" "elements M'"]
          by auto
        from ‹var l  vars (elements M'')
        have "¬ literalTrue l (elements M'')" "¬ literalFalse l (elements M'')"
          using valuationContainsItsLiteralsVariable[of "l" "elements M''"]
          using valuationContainsItsLiteralsVariable[of "opposite l" "elements M''"]
          by auto
        have "uniq (elements M)"
          using M = M' @ [(l, d)] @ M'' ‹uniq (elements (M' @ M''))
            ¬ literalTrue l (elements M'') ¬ literalFalse l (elements M'')
            ¬ literalTrue l (elements M') ¬ literalFalse l (elements M')
          by (auto iff: uniqAppendIff)
        moreover
        have "consistent (elements M)"
        proof-
          {
            assume "¬ consistent (elements M)"
            then obtain l' where "literalTrue l' (elements M)" "literalFalse l' (elements M)"
              by (auto simp add: inconsistentCharacterization)
            have False 
            proof (cases "l' = l")
              case True
              with ‹literalFalse l' (elements M) M = M' @ [(l, d)] @ M'' 
              have "literalFalse l' (elements (M' @ M''))"
                using oppositeIsDifferentFromLiteral[of "l"]
                by (auto split: if_split_asm)
              with ¬ literalFalse l (elements M') ¬ literalFalse l (elements M'') l' = l
              show ?thesis
                by auto
            next
              case False
              with ‹literalTrue l' (elements M) M = M' @ [(l, d)] @ M'' 
              have "literalTrue l' (elements (M' @ M''))"
                by (auto split: if_split_asm)
              with ‹consistent (elements (M' @ M''))
              have "¬ literalFalse l' (elements (M' @ M''))"
                by (auto simp add: inconsistentCharacterization)
              with ‹literalFalse l' (elements M) M = M' @ [(l, d)] @ M'' 
              have "opposite l' = l"
                by (auto split: if_split_asm)
              with ‹var l = v
              have "var l' = v"
                by auto
              with ‹literalTrue l' (elements (M' @ M'')) ‹vars (elements (M' @ M'')) = V'
              have "v  V'"
                using valuationContainsItsLiteralsVariable[of "l'" "elements (M' @ M'')"]
                by simp
              with v  V'
              show ?thesis
                by simp
            qed
          }
          thus ?thesis
            by auto
        qed
        ultimately
        show "M  ?lhs"
          by auto
      qed
    qed
    moreover
    let ?f = "λ ((M', M''), l, d). M' @ [(l, d)] @ M''"
    let ?Mset = "{(M', M''). M' @ M''  ?trails V'}"
    let ?lSet = "{Pos v, Neg v}"
    let ?dSet = "{True, False}"
    have "?trails' V' = ?f ` (?Mset × ?lSet × ?dSet)" (is "?lhs = ?rhs")
    proof
      show "?lhs  ?rhs"
      proof
        fix M :: LiteralTrail
        assume "M  ?lhs"
        then obtain M' M'' l d
          where P: "M = M' @ [(l, d)] @ M''" "M' @ M''  (?trails V')" "l  {Pos v, Neg v}" "d  {True, False}"
          by auto
        show "M  ?rhs"
        proof
          from P
          show "M = ?f ((M', M''), l, d)"
            by simp
        next
          from P
          show "((M', M''), l, d)  ?Mset × ?lSet × ?dSet"
            by auto
        qed
      qed
    next
      show "?rhs  ?lhs"
      proof
        fix M::LiteralTrail
        assume "M  ?rhs"
        then obtain p l d where P: "M = ?f (p, l, d)" "p  ?Mset" "l  ?lSet" "d  ?dSet"
          by auto
        from p  ?Mset
        obtain M' M'' where "M' @ M''  ?trails V'"
          by auto
        thus "M  ?lhs"
          using P
          by auto
      qed
    qed
    moreover
    have "?Mset = {(M', M'').  l. l  ?trails V'  l = M' @ M''}"
      by auto
    hence "finite ?Mset"
      using insert(3)
      using finiteListDecomposeSet[of "?trails V'"]
      by simp
    ultimately
    show ?thesis
      by auto
  qed
qed

lemma finiteUniqAndConsistentTrailsWithGivenVariableSuperset: 
  fixes V :: "Variable set"
  assumes "finite V"
  shows "finite {(M::LiteralTrail). vars (elements M)  V  uniq (elements M)  consistent (elements M)}" (is "finite (?trails V)")
proof-
  have "{M. vars (elements M)  V  uniq (elements M)  consistent (elements M)} = 
    ( v  Pow V.{M. vars (elements M) = v  uniq (elements M)  consistent (elements M)})"
    by auto
  moreover
  have "finite ( v  Pow V.{M. vars (elements M) = v  uniq (elements M)  consistent (elements M)})"
  proof (rule finite_UN_I)
    from ‹finite V
    show "finite (Pow V)"
      by simp
  next
    fix v
    assume "v  Pow V"
    with ‹finite V
    have "finite v"
      by (auto simp add: finite_subset)
    thus "finite {M. vars (elements M) = v  uniq (elements M)  consistent (elements M)}"
      using finiteUniqAndConsistentTrailsWithGivenVariableSet[of "v"]
      by simp
  qed
  ultimately
  show ?thesis
    by simp
qed

text‹Since the restricted ordering is acyclic and its domain is
finite, it has to be well-founded.›
lemma wfLexLessRestricted:
  assumes "finite Vbl"
  shows "wf (lexLessRestricted Vbl)"
proof (rule finite_acyclic_wf)
  show "finite (lexLessRestricted Vbl)"
  proof-
    let ?X = "{(M1, M2). 
      consistent (elements M1)  uniq (elements M1)  vars (elements M1)  Vbl 
      consistent (elements M2)  uniq (elements M2)  vars (elements M2)  Vbl}"
    let ?Y = "{M. vars (elements M)  Vbl  uniq (elements M)  consistent (elements M)}"
    have "?X = ?Y × ?Y"
      by auto
    moreover
    have "finite ?Y"
      using finiteUniqAndConsistentTrailsWithGivenVariableSuperset[of "Vbl"]
        ‹finite Vbl
      by auto
    ultimately
    have "finite ?X"
      by simp
    moreover
    have "lexLessRestricted Vbl  ?X"
      unfolding lexLessRestricted_def
      by auto
    ultimately
    show ?thesis
      by (simp add: finite_subset)
  qed
next
  show "acyclic (lexLessRestricted Vbl)"
  proof-
    {
      assume "¬ ?thesis"
      then obtain x where "(x, x)  (lexLessRestricted Vbl)^+"
        unfolding acyclic_def
        by auto
      have "lexLessRestricted Vbl  lexLess"
        unfolding lexLessRestricted_def
        by auto
      have "(lexLessRestricted Vbl)^+  lexLess^+"
      proof
        fix a
        assume "a  (lexLessRestricted Vbl)^+"
        with ‹lexLessRestricted Vbl  lexLess›
        show "a  lexLess^+"
          using trancl_mono[of "a" "lexLessRestricted Vbl" "lexLess"]
          by blast
      qed
      with (x, x)  (lexLessRestricted Vbl)^+
      have "(x, x)  lexLess^+"
        by auto
      moreover
      have "trans lexLess"
        using translexLess
        .
      hence "lexLess^+ = lexLess"
        by (rule trancl_id)
      ultimately
      have "(x, x)  lexLess"
        by auto
      with irreflexiveLexLess[of "x"]
      have False
        by simp
    }
    thus ?thesis
      by auto
  qed
qed

text@{term lexLessRestricted} is also transitive.›
lemma transLexLessRestricted:
  shows "trans (lexLessRestricted Vbl)"
proof-
  {
    fix x::LiteralTrail and y::LiteralTrail and z::LiteralTrail
    assume "(x, y)  lexLessRestricted Vbl" "(y, z)  lexLessRestricted Vbl"
    hence "(x, z)  lexLessRestricted Vbl"
      unfolding lexLessRestricted_def
      using translexLess
      unfolding trans_def
      by auto
  }
  thus ?thesis
    unfolding trans_def
    by blast
qed


(*-----------------------------------------------------------------------*)
subsubsection‹Conflict clause ordering›
(*-----------------------------------------------------------------------*)

text‹The ordering of conflict clauses is the multiset ordering induced by the ordering of elements in the trail.
Since, resolution operator is defined so that it removes all occurrences of clashing literal, it is also neccessary 
to remove duplicate literals before comparison.›

definition
"multLess M = inv_image  (mult (precedesOrder (elements M))) (λ x. mset (remdups (oppositeLiteralList x)))"

text‹The following lemma will help prove that application of the
$Explain$ DPLL transition rule decreases the conflict clause in the
@{term multLess} ordering.›
lemma multLessResolve:
  assumes 
  "opposite l el C" and
  "isReason reason l (elements M)"
  shows
  "(resolve C reason (opposite l), C)  multLess  M"
proof-
  let ?X = "mset (remdups (oppositeLiteralList C))"
  let ?Y = "mset (remdups (oppositeLiteralList (resolve C reason (opposite l))))"
  let ?ord = "precedesOrder (elements M)"
  have "(?Y, ?X)  (mult1 ?ord)"
  proof-
    let ?Z = "mset (remdups (oppositeLiteralList (removeAll (opposite l) C)))"
    let ?W = "mset (remdups (oppositeLiteralList (removeAll l (list_diff reason C))))"
    let ?a = "l"
    from (opposite l) el C
    have "?X = ?Z + {#?a#}"
      using removeAll_multiset[of "remdups (oppositeLiteralList C)" "l"]
      using oppositeLiteralListRemove[of "opposite l" "C"]
      using literalElListIffOppositeLiteralElOppositeLiteralList[of "l" "oppositeLiteralList C"]
      by auto
    moreover
    have "?Y = ?Z + ?W" 
    proof-
      have "list_diff (oppositeLiteralList (removeAll l reason)) (oppositeLiteralList (removeAll (opposite l) C)) = 
        oppositeLiteralList (removeAll l (list_diff reason C))"
      proof-
        from ‹isReason reason l (elements M)
        have "opposite l  set (removeAll l reason)"
          unfolding isReason_def
          by auto
        
        hence "list_diff (removeAll l reason) (removeAll (opposite l) C) = list_diff (removeAll l reason) C"
          using listDiffRemoveAllNonMember[of "opposite l" "removeAll l reason" "C"]
          by simp
        thus ?thesis
          unfolding oppositeLiteralList_def
          using listDiffMap[of "opposite" "removeAll l reason" "removeAll (opposite l) C"]
          by auto
      qed
      thus ?thesis
        unfolding resolve_def
        using remdupsAppendMultiSet[of "oppositeLiteralList (removeAll (opposite l) C)" "oppositeLiteralList (removeAll l reason)"]
        unfolding oppositeLiteralList_def
        by auto
    qed
    moreover
    have " b. b ∈# ?W  (b, ?a)  ?ord"
    proof-
      {
        fix b
        assume "b ∈# ?W"
        hence "opposite b  set (removeAll l reason)"
        proof-
          from b ∈# ?W 
          have "b el remdups (oppositeLiteralList (removeAll l (list_diff reason C)))"
            by simp
          hence "opposite b el removeAll l (list_diff reason C)"
            using literalElListIffOppositeLiteralElOppositeLiteralList[of "opposite b" "removeAll l (list_diff reason C)"]
            by auto
          hence "opposite b el list_diff (removeAll l reason) C"
            by simp
          thus ?thesis
            using listDiffIff[of "opposite b" "removeAll l reason" "C"]
            by simp
        qed
        with ‹isReason reason l (elements M)
        have "precedes b l (elements M)" "b  l"
          unfolding isReason_def
          unfolding precedes_def
          by auto
        hence "(b, ?a)  ?ord"
          unfolding precedesOrder_def
          by simp
      }
      thus ?thesis
        by auto
    qed
    ultimately
    have " a M0 K. ?X = M0 + {#a#}  ?Y = M0 + K  (b. b ∈# K  (b, a)  ?ord)"
      by blast
    thus ?thesis
      unfolding mult1_def
      by auto
  qed
  hence "(?Y, ?X)  (mult1 ?ord)+"
    by simp
  thus ?thesis
    unfolding multLess_def
    unfolding mult_def
    unfolding inv_image_def
    by auto
qed

lemma multLessListDiff:
assumes 
  "(a, b)  multLess M"
shows
  "(list_diff a x, b)  multLess M"
proof-
  let ?pOrd = "precedesOrder (elements M)"
  let ?f = "λ l. remdups (map opposite l)"
  have "trans ?pOrd"
    using transPrecedesOrder[of "elements M"]
    by simp

  have  "(mset (?f a), mset (?f b))  mult ?pOrd"
    using assms
    unfolding multLess_def
    unfolding oppositeLiteralList_def
    by simp
  moreover
  have "multiset_le (mset (list_diff (?f a) (?f x)))
                    (mset (?f a))
                    ?pOrd"
    using ‹trans ?pOrd
    using multisetLeListDiff[of "?pOrd" "?f a" "?f x"]
    by simp
  ultimately
  have "(mset (list_diff (?f a) (?f x)), mset (?f b))  mult ?pOrd"
    unfolding multiset_le_def
    unfolding mult_def
    by auto

  thus ?thesis
    unfolding multLess_def
    unfolding oppositeLiteralList_def
    by (simp add: listDiffMap remdupsListDiff)
qed

lemma multLessRemdups:
assumes 
  "(a, b)  multLess M"
shows
  "(remdups a, remdups b)  multLess M  
   (remdups a, b)  multLess M  
   (a, remdups b)  multLess M"
proof-
  {
    fix l
    have "remdups (map opposite l) = remdups (map opposite (remdups l))"
      by (induct l) auto
  }
  thus ?thesis
    using assms
    unfolding multLess_def
    unfolding oppositeLiteralList_def
    by simp
qed

text‹Now we show that @{term multLess} is well-founded.›
lemma wfMultLess: 
  shows "wf (multLess M)"
proof-
  have "wf (precedesOrder (elements M))"
    by (simp add: wellFoundedPrecedesOrder)
  hence "wf (mult (precedesOrder (elements M)))"
    by (simp add: wf_mult)
  thus ?thesis
    unfolding multLess_def
    using wf_inv_image[of "(mult (precedesOrder (elements M)))"]
    by auto
qed


(*-----------------------------------------------------------------------*)
subsubsection‹ConflictFlag ordering›
(*-----------------------------------------------------------------------*)

text‹A trivial ordering on Booleans. It will be used for the
$Conflict$ transition rule.›
definition
  "boolLess = {(True, False)}"

text‹We show that it is well-founded›
lemma transBoolLess:
  shows "trans boolLess"
proof-
  {
    fix x::bool and y::bool and z::bool
    assume "(x, y)  boolLess"
    hence "x = True" "y = False"
      unfolding boolLess_def
      by auto
    assume "(y, z)  boolLess"
    hence "y = True" "z = False"
      unfolding boolLess_def
      by auto
    from y = False› y = True›
    have False
      by simp
    hence "(x, z)  boolLess"
      by simp
  }
  thus ?thesis
    unfolding trans_def
    by blast
qed

lemma wfBoolLess:
  shows "wf boolLess"
proof (rule finite_acyclic_wf)
  show "finite boolLess"
    unfolding boolLess_def
    by simp
next
  have "boolLess^+ = boolLess"
    using transBoolLess
    by simp
  thus "acyclic boolLess"
    unfolding boolLess_def
    unfolding acyclic_def
    by auto
qed


(*-----------------------------------------------------------------------*)
subsubsection‹Formulae ordering›
(*-----------------------------------------------------------------------*)

text‹A partial ordering of formulae, based on a membersip of a
single fixed clause. This ordering will be used for the $Learn$
transtion rule.›
definition "learnLess (C::Clause) == {((F1::Formula), (F2::Formula)). C el F1  ¬ C el F2}"

text‹We show that it is well founded›
lemma wfLearnLess:
  fixes C::Clause
  shows "wf (learnLess C)"
unfolding wf_eq_minimal
proof-
    show "Q F. F  Q  (FminQ. F'. (F', Fmin)  learnLess C  F'  Q)"
    proof-
      {
        fix F::Formula and Q::"Formula set"
        assume "F  Q"
        have "FminQ. F'. (F', Fmin)  learnLess C  F'  Q"
        proof (cases " Fc  Q. C el Fc")
          case True
          then obtain Fc where "Fc  Q" "C el Fc"
            by auto
          have "F'. (F', Fc)  learnLess C  F'  Q"
          proof
            fix F'
            show "(F', Fc)  learnLess C  F'  Q"
            proof
              assume "(F', Fc)  learnLess C"
              hence "¬ C el Fc"
                unfolding learnLess_def
                by auto
              with C el Fc have False
                by simp
              thus "F'  Q"
                by simp
            qed
          qed
          with Fc  Q
          show ?thesis
            by auto
        next
          case False
          have "F'. (F', F)  learnLess C  F'  Q"
          proof
            fix F'
            show "(F', F)  learnLess C  F'  Q"
            proof
              assume "(F', F)  learnLess C"
              hence "C el F'"
                unfolding learnLess_def
                by simp
              with False
              show "F'  Q"
                by auto
            qed
          qed
          with F  Q 
          show ?thesis
            by auto
        qed
      }
      thus ?thesis
        by auto
    qed
qed

(*-----------------------------------------------------------------------*)
subsubsection‹Properties of well-founded relations.›
(*-----------------------------------------------------------------------*)
lemma wellFoundedEmbed: 
  fixes rel :: "('a × 'a) set" and rel' :: "('a × 'a) set"
  assumes " x y. (x, y)  rel  (x, y)  rel'" and "wf rel'"
  shows "wf rel"
unfolding wf_eq_minimal
proof-
  show "Q x. x  Q  (zminQ. z. (z, zmin)  rel  z  Q)"
  proof-
    {
      fix x::"'a" and Q::"'a set"
      assume "x  Q"
      have "zminQ. z. (z, zmin)  rel  z  Q"
      proof-
        from ‹wf rel' x  Q
        obtain zmin::"'a"
          where "zmin  Q" and "z. (z, zmin)  rel'  z  Q"
          unfolding wf_eq_minimal
          by auto
        {
          fix z::"'a"
          assume "(z, zmin)  rel"
          have "z  Q"
          proof-
            from  x y. (x, y)  rel  (x, y)  rel' (z, zmin)  rel
            have "(z, zmin)  rel'"
              by simp
            with z. (z, zmin)  rel'  z  Q
            show ?thesis
              by simp
          qed
        }
        with zmin  Q
        show ?thesis
          by auto
      qed
    }
    thus ?thesis
      by auto
  qed
qed

end

Theory BasicDPLL

(*    Title:              SatSolverVerification/BasicDPLL.thy
      Author:             Filip Maric
      Maintainer:         Filip Maric <filip at matf.bg.ac.yu>
*)

section‹BasicDPLL›
theory BasicDPLL
imports SatSolverVerification
begin

text‹This theory formalizes the transition rule system BasicDPLL
 which is based on the classical DPLL procedure, but does not use the
 PureLiteral rule.›

(******************************************************************************)
subsection‹Specification›
(******************************************************************************)

text‹The state of the procedure is uniquely determined by its trail.›
record State = 
"getM" :: LiteralTrail

text‹Procedure checks the satisfiability of the formula F0 which
  does not change during the solving process. An external parameter is
  the set @{term decisionVars} which are the variables that branching
  is performed on. Usually this set contains all variables of the
  formula F0, but that does not always have to be the case.›


text‹Now we define the transition rules of the system›
definition
appliedDecide:: "State  State  Variable set  bool"
where
"appliedDecide stateA stateB decisionVars == 
   l. 
        (var l)  decisionVars  
        ¬ l el (elements (getM stateA))  
        ¬ opposite l el (elements (getM stateA)) 

        getM stateB = getM stateA @ [(l, True)]
"
definition
applicableDecide :: "State  Variable set  bool"
where
"applicableDecide state decisionVars ==  state'. appliedDecide state state' decisionVars"

definition
appliedUnitPropagate :: "State  State  Formula  bool"
where
"appliedUnitPropagate stateA stateB F0 == 
   (uc::Clause) (ul::Literal). 
       uc el F0  
       isUnitClause uc ul (elements (getM stateA))  

       getM stateB = getM stateA @ [(ul, False)]
"
definition
applicableUnitPropagate :: "State  Formula  bool"
where
"applicableUnitPropagate state F0 ==  state'. appliedUnitPropagate state state' F0"

definition
appliedBacktrack :: "State  State  Formula  bool"
where
"appliedBacktrack stateA stateB F0 == 
      formulaFalse F0 (elements (getM stateA))  
      decisions (getM stateA)  []  

      getM stateB = prefixBeforeLastDecision (getM stateA) @ [(opposite (lastDecision (getM stateA)), False)]
"
definition
applicableBacktrack :: "State  Formula  bool"
where
"applicableBacktrack state F0 ==   state'. appliedBacktrack state state' F0"


text‹Solving starts with the empty trail.›
definition
isInitialState :: "State  Formula  bool"
where
"isInitialState state F0 == 
      getM state = []
"
text‹Transitions are preformed only by using one of the three given rules.›
definition
"transition stateA stateB F0 decisionVars == 
     appliedDecide        stateA stateB decisionVars 
     appliedUnitPropagate stateA stateB F0   
     appliedBacktrack     stateA stateB F0
"

text‹Transition relation is obtained by applying transition rules
iteratively. It is defined using a reflexive-transitive closure.›
definition
"transitionRelation F0 decisionVars == ({(stateA, stateB). transition stateA stateB F0 decisionVars})^*"

text‹Final state is one in which no rules apply›
definition
isFinalState :: "State  Formula  Variable set  bool"
where
"isFinalState state F0 decisionVars == ¬ ( state'. transition state state' F0 decisionVars)"

text‹The following several lemmas give conditions for applicability of different rules.›
lemma applicableDecideCharacterization:
  fixes stateA::State
  shows "applicableDecide stateA decisionVars = 
  ( l. 
        (var l)  decisionVars  
        ¬ l el (elements (getM stateA))  
        ¬ opposite l el (elements (getM stateA))) 
  " (is "?lhs = ?rhs")
proof
  assume ?rhs
  then obtain l where 
    *: "(var l)  decisionVars" "¬ l el (elements (getM stateA))" "¬ opposite l el (elements (getM stateA))"
    unfolding applicableDecide_def
    by auto
  let ?stateB = "stateA getM := (getM stateA) @ [(l, True)] "
  from * have "appliedDecide stateA ?stateB decisionVars"
    unfolding appliedDecide_def
    by auto
  thus ?lhs
    unfolding applicableDecide_def
    by auto
next
  assume ?lhs
  then obtain stateB l
    where "(var l)  decisionVars" "¬ l el (elements (getM stateA))"
    "¬ opposite l el (elements (getM stateA))"
    unfolding applicableDecide_def
    unfolding appliedDecide_def
    by auto
  thus ?rhs
    by auto
qed

lemma applicableUnitPropagateCharacterization:
  fixes stateA::State and F0::Formula
  shows "applicableUnitPropagate stateA F0 = 
  ( (uc::Clause) (ul::Literal). 
       uc el F0  
       isUnitClause uc ul (elements (getM stateA)))
  " (is "?lhs = ?rhs")
proof
  assume "?rhs"
  then obtain ul uc 
    where *: "uc el F0" "isUnitClause uc ul (elements (getM stateA))"
    unfolding applicableUnitPropagate_def
    by auto
  let ?stateB = "stateA getM := getM stateA @ [(ul, False)] "
  from * have "appliedUnitPropagate stateA ?stateB F0" 
    unfolding appliedUnitPropagate_def
    by auto
  thus ?lhs
    unfolding applicableUnitPropagate_def
    by auto
next
  assume ?lhs
  then obtain stateB uc ul
    where "uc el F0" "isUnitClause uc ul (elements (getM stateA))"
    unfolding applicableUnitPropagate_def
    unfolding appliedUnitPropagate_def
    by auto
  thus ?rhs
    by auto
qed

lemma applicableBacktrackCharacterization:
  fixes stateA::State
  shows "applicableBacktrack stateA F0 = 
      (formulaFalse F0 (elements (getM stateA))  
       decisions (getM stateA)  [])" (is "?lhs = ?rhs")
proof
  assume ?rhs
  hence *: "formulaFalse F0 (elements (getM stateA))" "decisions (getM stateA)  []"
    by auto
  let ?stateB = "stateA getM := prefixBeforeLastDecision (getM stateA) @ [(opposite (lastDecision (getM stateA)), False)]"
  from * have "appliedBacktrack stateA ?stateB F0"
    unfolding appliedBacktrack_def
    by auto
  thus ?lhs
    unfolding applicableBacktrack_def
    by auto
next
  assume "?lhs"
  then obtain stateB 
    where "appliedBacktrack stateA stateB F0"
    unfolding applicableBacktrack_def
    by auto
  hence 
    "formulaFalse F0 (elements (getM stateA))"
    "decisions (getM stateA)  []"
    "getM stateB = prefixBeforeLastDecision (getM stateA) @ [(opposite (lastDecision (getM stateA)), False)]"
    unfolding appliedBacktrack_def
    by auto
  thus ?rhs
    by auto
qed

text‹Final states are the ones where no rule is applicable.›
lemma finalStateNonApplicable: 
  fixes state::State
  shows "isFinalState state F0 decisionVars = 
          (¬ applicableDecide state decisionVars  
           ¬ applicableUnitPropagate state F0  
           ¬ applicableBacktrack state F0)"
unfolding isFinalState_def
unfolding transition_def
unfolding applicableDecide_def
unfolding applicableUnitPropagate_def
unfolding applicableBacktrack_def
by auto
  
(******************************************************************************)
subsection‹Invariants›
(******************************************************************************)
text‹Invariants that are relevant for the rest of correctness proof.›
definition
invariantsHoldInState :: "State  Formula  Variable set  bool"
where
"invariantsHoldInState state F0 decisionVars == 
    InvariantImpliedLiterals F0 (getM state) 
    InvariantVarsM (getM state) F0 decisionVars 
    InvariantConsistent (getM state) 
    InvariantUniq (getM state)
"

text‹Invariants hold in initial states.›
lemma invariantsHoldInInitialState:
  fixes state :: State and F0 :: Formula
  assumes "isInitialState state F0" 
  shows "invariantsHoldInState state F0 decisionVars"
using assms
by (auto simp add:
  isInitialState_def 
  invariantsHoldInState_def 
  InvariantImpliedLiterals_def 
  InvariantVarsM_def
  InvariantConsistent_def
  InvariantUniq_def
)

text‹Valid transitions preserve invariants.›
lemma transitionsPreserveInvariants: 
  fixes stateA::State and stateB::State
  assumes "transition stateA stateB F0 decisionVars" and 
  "invariantsHoldInState stateA F0 decisionVars"
  shows "invariantsHoldInState stateB F0 decisionVars"
proof-
    from ‹invariantsHoldInState stateA F0 decisionVars
    have 
      "InvariantImpliedLiterals F0 (getM stateA)" and 
      "InvariantVarsM (getM stateA) F0 decisionVars" and
      "InvariantConsistent (getM stateA)" and
      "InvariantUniq (getM stateA)"
      unfolding invariantsHoldInState_def
      by auto
  {
    assume "appliedDecide stateA stateB decisionVars"
    then obtain l::Literal where
      "(var l)  decisionVars"
      "¬ literalTrue l (elements (getM stateA))"
      "¬ literalFalse l (elements (getM stateA))"
      "getM stateB = getM stateA @ [(l, True)]"
      unfolding appliedDecide_def
      by auto

    from ¬ literalTrue l (elements (getM stateA)) ¬ literalFalse l (elements (getM stateA)) 
    have *: "var l  vars (elements (getM stateA))"
      using variableDefinedImpliesLiteralDefined[of "l" "elements (getM stateA)"]
      by simp

    have "InvariantImpliedLiterals F0 (getM stateB)"
      using 
        ‹getM stateB = getM stateA @ [(l, True)] 
        ‹InvariantImpliedLiterals F0 (getM stateA)
        ‹InvariantUniq (getM stateA)
        ‹var l  vars (elements (getM stateA))
        InvariantImpliedLiteralsAfterDecide[of "F0" "getM stateA" "l" "getM stateB"]
      by simp
    moreover
    have "InvariantVarsM (getM stateB) F0 decisionVars"
      using ‹getM stateB = getM stateA @ [(l, True)] 
        ‹InvariantVarsM (getM stateA) F0 decisionVars
        ‹var l  decisionVars
        InvariantVarsMAfterDecide[of "getM stateA" "F0" "decisionVars" "l" "getM stateB"]
      by simp
    moreover 
    have "InvariantConsistent (getM stateB)"
      using ‹getM stateB = getM stateA @ [(l, True)] 
        ‹InvariantConsistent (getM stateA)
        ‹var l  vars (elements (getM stateA))
        InvariantConsistentAfterDecide[of "getM stateA" "l" "getM stateB"]
      by simp
    moreover
    have "InvariantUniq (getM stateB)"
      using ‹getM stateB = getM stateA @ [(l, True)] 
        ‹InvariantUniq (getM stateA)
        ‹var l  vars (elements (getM stateA))
        InvariantUniqAfterDecide[of "getM stateA" "l" "getM stateB"]
      by simp
    ultimately
    have ?thesis
      unfolding invariantsHoldInState_def
      by auto
  }
  moreover
  {
    assume "appliedUnitPropagate stateA stateB F0"
    then obtain uc::Clause and ul::Literal where 
      "uc el F0"
      "isUnitClause uc ul (elements (getM stateA))"
      "getM stateB = getM stateA @ [(ul, False)]"
      unfolding appliedUnitPropagate_def
      by auto

    from ‹isUnitClause uc ul (elements (getM stateA))
    have "ul el uc"
      unfolding isUnitClause_def
      by simp

    from uc el F0
    have "formulaEntailsClause F0 uc"
      by (simp add: formulaEntailsItsClauses)
    
    have "InvariantImpliedLiterals F0 (getM stateB)"
      using
        ‹InvariantImpliedLiterals F0 (getM stateA) 
        ‹formulaEntailsClause F0 uc
        ‹isUnitClause uc ul (elements (getM stateA))
        ‹getM stateB = getM stateA @ [(ul, False)]
        InvariantImpliedLiteralsAfterUnitPropagate[of "F0" "getM stateA" "uc" "ul" "getM stateB"]
      by simp
    moreover
    from ul el uc uc el F0
    have "ul el F0"
      by (auto simp add: literalElFormulaCharacterization)
    hence "var ul  vars F0  decisionVars"
      using formulaContainsItsLiteralsVariable [of "ul" "F0"]
      by auto

    have "InvariantVarsM (getM stateB) F0 decisionVars"
      using ‹InvariantVarsM (getM stateA) F0 decisionVars
        ‹var ul  vars F0  decisionVars
        ‹getM stateB = getM stateA @ [(ul, False)]
        InvariantVarsMAfterUnitPropagate[of "getM stateA" "F0" "decisionVars" "ul" "getM stateB"]
      by simp
    moreover
    have "InvariantConsistent (getM stateB)"
      using ‹InvariantConsistent (getM stateA)
        ‹isUnitClause uc ul (elements (getM stateA))
        ‹getM stateB = getM stateA @ [(ul, False)]
        InvariantConsistentAfterUnitPropagate [of "getM stateA" "uc" "ul" "getM stateB"]
      by simp
    moreover
    have "InvariantUniq (getM stateB)"
      using ‹InvariantUniq (getM stateA)
        ‹isUnitClause uc ul (elements (getM stateA))
        ‹getM stateB = getM stateA @ [(ul, False)]
        InvariantUniqAfterUnitPropagate [of "getM stateA" "uc" "ul" "getM stateB"]
      by simp
    ultimately
    have ?thesis
      unfolding invariantsHoldInState_def
      by auto
  }
  moreover
  {
    assume "appliedBacktrack stateA stateB F0"
    hence "formulaFalse F0 (elements (getM stateA))" 
      "formulaFalse F0 (elements (getM stateA))"
      "decisions (getM stateA)  []"
      "getM stateB = prefixBeforeLastDecision (getM stateA) @ [(opposite (lastDecision (getM stateA)), False)]"
      unfolding appliedBacktrack_def
      by auto      

    have "InvariantImpliedLiterals F0 (getM stateB)"
      using ‹InvariantImpliedLiterals F0 (getM stateA)
        ‹formulaFalse F0 (elements (getM stateA))
        ‹decisions (getM stateA)  []
        ‹getM stateB = prefixBeforeLastDecision (getM stateA) @ [(opposite (lastDecision (getM stateA)), False)]
        ‹InvariantUniq (getM stateA)
        ‹InvariantConsistent (getM stateA)
        InvariantImpliedLiteralsAfterBacktrack[of "F0" "getM stateA" "getM stateB"]
      by simp
    moreover
    have "InvariantVarsM (getM stateB) F0 decisionVars"
      using ‹InvariantVarsM (getM stateA) F0 decisionVars
        ‹decisions (getM stateA)  []
        ‹getM stateB = prefixBeforeLastDecision (getM stateA) @ [(opposite (lastDecision (getM stateA)), False)]
        InvariantVarsMAfterBacktrack[of "getM stateA" "F0" "decisionVars" "getM stateB"]
      by simp
    moreover
    have "InvariantConsistent (getM stateB)"
      using ‹InvariantConsistent (getM stateA)
        ‹InvariantUniq (getM stateA)
        ‹decisions (getM stateA)  []
        ‹getM stateB = prefixBeforeLastDecision (getM stateA) @ [(opposite (lastDecision (getM stateA)), False)]
        InvariantConsistentAfterBacktrack[of "getM stateA" "getM stateB"]
      by simp
    moreover
    have "InvariantUniq (getM stateB)"
      using ‹InvariantConsistent (getM stateA)
        ‹InvariantUniq (getM stateA)
        ‹decisions (getM stateA)  []
        ‹getM stateB = prefixBeforeLastDecision (getM stateA) @ [(opposite (lastDecision (getM stateA)), False)]
        InvariantUniqAfterBacktrack[of "getM stateA" "getM stateB"]
      by simp
    ultimately
    have ?thesis
      unfolding invariantsHoldInState_def
      by auto
  }
  ultimately
  show ?thesis
    using ‹transition stateA stateB F0 decisionVars
    unfolding transition_def
    by auto
qed

text‹The consequence is that invariants hold in all valid runs.›
lemma invariantsHoldInValidRuns: 
  fixes F0 :: Formula and decisionVars :: "Variable set"
  assumes "invariantsHoldInState stateA F0 decisionVars" and
  "(stateA, stateB)  transitionRelation F0 decisionVars"
  shows "invariantsHoldInState stateB F0 decisionVars"
using assms
using transitionsPreserveInvariants
using rtrancl_induct[of "stateA" "stateB" 
  "{(stateA, stateB). transition stateA stateB F0 decisionVars}" "λ x. invariantsHoldInState x F0 decisionVars"]
unfolding transitionRelation_def
by auto

lemma invariantsHoldInValidRunsFromInitialState:
  fixes F0 :: Formula and decisionVars :: "Variable set"
  assumes "isInitialState state0 F0" 
  and "(state0, state)  transitionRelation F0 decisionVars"
  shows "invariantsHoldInState state F0 decisionVars"
proof-
  from ‹isInitialState state0 F0
  have "invariantsHoldInState state0 F0 decisionVars"
    by (simp add:invariantsHoldInInitialState)
  with assms
  show ?thesis
    using invariantsHoldInValidRuns [of "state0"  "F0" "decisionVars" "state"]
    by simp
qed

text‹
 In the following text we will show that there are two kinds of states:
 \begin{enumerate}
  \item \textit{UNSAT} states where @{term "formulaFalse F0 (elements (getM state))"}
  and @{term "decisions (getM state) = []"}. 
  \item \textit{SAT} states where @{term "¬ formulaFalse F0 (elements (getM state))"}
  and @{term "vars (elements (getM state))  decisionVars"}.
 \end{enumerate}
  
 The soundness theorems claim that if \textit{UNSAT} state is reached
 the formula is unsatisfiable and if \textit{SAT} state is reached,
 the formula is satisfiable.

 Completeness theorems claim that every final state is either
 \textit{UNSAT} or \textit{SAT}. A consequence of this and soundness
 theorems, is that if formula is unsatisfiable the solver will finish
 in an \textit{UNSAT} state, and if the formula is satisfiable the
 solver will finish in a \textit{SAT} state.›


(******************************************************************************)
subsection‹Soundness›
(******************************************************************************)

(*----------------------------------------------------------------------------*)
theorem soundnessForUNSAT:
  fixes F0 :: Formula and decisionVars :: "Variable set" and state0 :: State and state :: State
  assumes
  "isInitialState state0 F0" and
  "(state0, state)  transitionRelation F0 decisionVars"

  "formulaFalse F0 (elements (getM state))"
  "decisions (getM state) = []"
  shows "¬ satisfiable F0"
(*----------------------------------------------------------------------------*)
proof-
  from ‹isInitialState state0 F0 (state0, state)  transitionRelation F0 decisionVars
  have "invariantsHoldInState state F0 decisionVars" 
    using invariantsHoldInValidRunsFromInitialState
    by simp
  hence "InvariantImpliedLiterals F0 (getM state)"
    unfolding invariantsHoldInState_def
    by auto
  with ‹formulaFalse F0 (elements (getM state))
    ‹decisions (getM state) = []
  show ?thesis
    using unsatReport[of "F0" "getM state" "F0"]
    unfolding InvariantEquivalent_def equivalentFormulae_def
    by simp
qed

(*----------------------------------------------------------------------------*)
theorem soundnessForSAT:
  fixes F0 :: Formula and decisionVars :: "Variable set" and state0 :: State and state :: State
  assumes
  "vars F0  decisionVars" and

  "isInitialState state0 F0" and
  "(state0, state)  transitionRelation F0 decisionVars"

  "¬ formulaFalse F0 (elements (getM state))"
  "vars (elements (getM state))  decisionVars"  

  shows 
  "model (elements (getM state)) F0"
(*----------------------------------------------------------------------------*)
proof-
  from ‹isInitialState state0 F0 (state0, state)  transitionRelation F0 decisionVars
  have "invariantsHoldInState state F0 decisionVars" 
    using invariantsHoldInValidRunsFromInitialState
    by simp
  hence 
    "InvariantConsistent (getM state)" 
    unfolding invariantsHoldInState_def
    by auto
  with assms
  show ?thesis
  using satReport[of "F0" "decisionVars" "F0" "getM state"]
  unfolding InvariantEquivalent_def equivalentFormulae_def
  InvariantVarsF_def
  by auto
qed


(******************************************************************************)
subsection‹Termination›
(******************************************************************************)
text‹We now define a termination ordering on the set of states based
on the @{term lexLessRestricted} trail ordering. This ordering will be central
in termination proof.›

definition "terminationLess (F0::Formula) decisionVars == {((stateA::State), (stateB::State)).
  (getM stateA, getM stateB)  lexLessRestricted (vars F0  decisionVars)}"


text‹We want to show that every valid transition decreases a state
  with respect to the constructed termination ordering. Therefore, we
  show that $Decide$, $UnitPropagate$ and $Backtrack$ rule decrease the
  trail with respect to the restricted trail ordering. Invariants
  ensure that trails are indeed @{term uniq}, @{term consistent} and with 
  finite variable sets.›
lemma trailIsDecreasedByDeciedUnitPropagateAndBacktrack:
  fixes stateA::State and stateB::State
  assumes "invariantsHoldInState stateA F0 decisionVars" and
  "appliedDecide stateA stateB decisionVars  appliedUnitPropagate stateA stateB F0  appliedBacktrack stateA stateB F0"
  shows "(getM stateB, getM stateA)  lexLessRestricted (vars F0  decisionVars)"
proof-
  from ‹appliedDecide stateA stateB decisionVars  appliedUnitPropagate stateA stateB F0  appliedBacktrack stateA stateB F0
    ‹invariantsHoldInState stateA F0 decisionVars 
  have "invariantsHoldInState stateB F0 decisionVars"
      using transitionsPreserveInvariants
      unfolding transition_def
      by auto
    from ‹invariantsHoldInState stateA F0 decisionVars 
    have *: "uniq (elements (getM stateA))" "consistent (elements (getM stateA))" "vars (elements (getM stateA))  vars F0  decisionVars"
      unfolding invariantsHoldInState_def
      unfolding InvariantVarsM_def
      unfolding InvariantConsistent_def
      unfolding InvariantUniq_def
      by auto
    from ‹invariantsHoldInState stateB F0 decisionVars 
    have **: "uniq (elements (getM stateB))" "consistent (elements (getM stateB))" "vars (elements (getM stateB))  vars F0  decisionVars"
      unfolding invariantsHoldInState_def
      unfolding InvariantVarsM_def
      unfolding InvariantConsistent_def
      unfolding InvariantUniq_def
      by auto
  {
    assume "appliedDecide stateA stateB decisionVars"
    hence "(getM stateB, getM stateA)  lexLess"
      unfolding appliedDecide_def
      by (auto simp add:lexLessAppend)
    with * ** 
    have "((getM stateB), (getM stateA))  lexLessRestricted (vars F0  decisionVars)"
      unfolding lexLessRestricted_def
      by auto
  }
  moreover
  {
    assume "appliedUnitPropagate stateA stateB F0"
    hence "(getM stateB, getM stateA)  lexLess"
      unfolding appliedUnitPropagate_def
      by (auto simp add:lexLessAppend)
    with * ** 
    have "(getM stateB, getM stateA)  lexLessRestricted (vars F0  decisionVars)"
      unfolding lexLessRestricted_def
      by auto
  }
  moreover
  {
    assume "appliedBacktrack stateA stateB F0"
    hence
      "formulaFalse F0 (elements (getM stateA))"
      "decisions (getM stateA)  []"
      "getM stateB = prefixBeforeLastDecision (getM stateA) @ [(opposite (lastDecision (getM stateA)), False)]"
      unfolding appliedBacktrack_def
      by auto
    hence "(getM stateB, getM stateA)  lexLess"
      using ‹decisions (getM stateA)  []
        ‹getM stateB = prefixBeforeLastDecision (getM stateA) @ [(opposite (lastDecision (getM stateA)), False)]
      by (simp add:lexLessBacktrack)
    with * ** 
    have "(getM stateB, getM stateA)  lexLessRestricted (vars F0  decisionVars)"
      unfolding lexLessRestricted_def
      by auto
  }
  ultimately
  show ?thesis
    using assms
    by auto
qed

text‹Now we can show that every rule application decreases a state
with respect to the constructed termination ordering.›
lemma stateIsDecreasedByValidTransitions:
  fixes stateA::State and stateB::State 
  assumes "invariantsHoldInState stateA F0 decisionVars" and "transition stateA stateB F0 decisionVars"
  shows "(stateB, stateA)  terminationLess F0 decisionVars"
proof-
  from ‹transition stateA stateB F0 decisionVars
  have "appliedDecide stateA stateB decisionVars  appliedUnitPropagate stateA stateB F0  appliedBacktrack stateA stateB F0"
    unfolding transition_def
    by simp 
  with ‹invariantsHoldInState stateA F0 decisionVars
  have "(getM stateB, getM stateA)  lexLessRestricted (vars F0  decisionVars)"
    using trailIsDecreasedByDeciedUnitPropagateAndBacktrack
    by simp
  thus ?thesis 
    unfolding terminationLess_def
    by simp
qed

text‹The minimal states with respect to the termination ordering are
  final i.e., no further transition rules are applicable.›
definition 
"isMinimalState stateMin F0 decisionVars == ( state::State. (state, stateMin)  terminationLess F0 decisionVars)"

lemma minimalStatesAreFinal:
  fixes stateA::State
  assumes "invariantsHoldInState state F0 decisionVars" and "isMinimalState state F0 decisionVars"
  shows "isFinalState state F0 decisionVars"
proof-
  {
    assume "¬ ?thesis"
    then obtain state'::State 
      where "transition state state' F0 decisionVars"
      unfolding isFinalState_def
      by auto
    with ‹invariantsHoldInState state F0 decisionVars 
    have "(state', state)  terminationLess F0 decisionVars"
      using stateIsDecreasedByValidTransitions[of "state" "F0" "decisionVars" "state'"]
      unfolding transition_def
      by auto
    with ‹isMinimalState state F0 decisionVars 
    have False
      unfolding isMinimalState_def
      by auto
  }
  thus ?thesis
    by auto
qed

text‹The following key lemma shows that the termination ordering is well founded.›
lemma wfTerminationLess: 
  fixes decisionVars :: "Variable set" and F0 :: "Formula"
  assumes "finite decisionVars"
  shows "wf (terminationLess F0 decisionVars)"
unfolding wf_eq_minimal
proof-
  show "Q state. state  Q  (stateMinQ. state'. (state', stateMin)  terminationLess F0 decisionVars  state'  Q)"
  proof-
    {
      fix Q :: "State set" and state :: State
      assume "state  Q"
      let ?Q1 = "{M::LiteralTrail.  state. state  Q  (getM state) = M}"
      from state  Q
      have "getM state  ?Q1"
        by auto
      from ‹finite decisionVars 
      have "finite (vars F0  decisionVars)"
        using finiteVarsFormula[of "F0"]
        by simp
      hence "wf (lexLessRestricted (vars F0  decisionVars))"
      using  wfLexLessRestricted[of "vars F0  decisionVars"]
      by simp
    with ‹getM state  ?Q1
      obtain Mmin where "Mmin  ?Q1" "M'. (M', Mmin)  lexLessRestricted (vars F0  decisionVars)  M'  ?Q1"
        unfolding wf_eq_minimal
        apply (erule_tac x="?Q1" in allE)
        apply (erule_tac x="getM state" in allE)
        by auto 
      from Mmin  ?Q1 obtain stateMin
        where "stateMin  Q" "(getM stateMin) = Mmin"
        by auto
      have "state'. (state', stateMin)  terminationLess F0 decisionVars  state'  Q"
      proof
        fix state'
        show "(state', stateMin)  terminationLess F0 decisionVars  state'  Q"
        proof
          assume "(state', stateMin)  terminationLess F0 decisionVars"
          hence "(getM state', getM stateMin)  lexLessRestricted (vars F0  decisionVars)"
            unfolding terminationLess_def
            by auto
          from M'. (M', Mmin)  lexLessRestricted (vars F0  decisionVars)  M'  ?Q1
            (getM state', getM stateMin)  lexLessRestricted (vars F0  decisionVars) ‹getM stateMin = Mmin
          have "getM state'  ?Q1"
            by simp
          with ‹getM stateMin = Mmin
          show "state'  Q"
            by auto
        qed
      qed
      with stateMin  Q
      have " stateMin  Q. (state'. (state', stateMin)  terminationLess F0 decisionVars  state'  Q)"
        by auto
    }
    thus ?thesis
      by auto
  qed
qed

text‹Using the termination ordering we show that the transition
relation is well founded on states reachable from initial state.›
(*----------------------------------------------------------------------------*)
theorem wfTransitionRelation:
  fixes decisionVars :: "Variable set" and F0 :: "Formula" and state0 :: "State"
  assumes "finite decisionVars" and "isInitialState state0 F0"
  shows "wf {(stateB, stateA). 
             (state0, stateA)  transitionRelation F0 decisionVars  (transition stateA stateB F0 decisionVars)}"
(*----------------------------------------------------------------------------*)
proof-
  let ?rel = "{(stateB, stateA). 
                  (state0, stateA)  transitionRelation F0 decisionVars  (transition stateA stateB F0 decisionVars)}"
  let ?rel'= "terminationLess F0 decisionVars"

  have "x y. (x, y)  ?rel  (x, y)  ?rel'"
  proof-
    {
      fix stateA::State and stateB::State
      assume "(stateB, stateA)  ?rel"
      hence "(stateB, stateA)  ?rel'"
        using ‹isInitialState state0 F0
        using invariantsHoldInValidRunsFromInitialState[of "state0" "F0" "stateA" "decisionVars"]
        using stateIsDecreasedByValidTransitions[of "stateA" "F0" "decisionVars" "stateB"]
        by simp
    }
    thus ?thesis
      by simp
  qed
  moreover 
  have "wf ?rel'"
    using ‹finite decisionVars
    by (rule wfTerminationLess)
  ultimately
  show ?thesis
    using wellFoundedEmbed[of "?rel" "?rel'"]
    by simp
qed



text‹We will now give two corollaries of the previous theorem. First
  is a weak termination result that shows that there is a terminating
  run from every intial state to the final one.›
corollary
  fixes decisionVars :: "Variable set" and F0 :: "Formula" and state0 :: "State"
  assumes "finite decisionVars" and "isInitialState state0 F0"
  shows " state. (state0, state)  transitionRelation F0 decisionVars  isFinalState state F0 decisionVars"
proof-
  {
    assume "¬ ?thesis"
    let ?Q = "{state. (state0, state)  transitionRelation F0 decisionVars}"
    let ?rel = "{(stateB, stateA). (state0, stateA)  transitionRelation F0 decisionVars 
                         transition stateA stateB F0 decisionVars}"
    have "state0  ?Q"
      unfolding transitionRelation_def
      by simp
    hence " state. state  ?Q"
      by auto

    from assms 
    have "wf ?rel"
      using wfTransitionRelation[of "decisionVars" "state0" "F0"]
      by auto
    hence " Q. ( x. x  Q)  ( stateMin  Q.  state. (state, stateMin)  ?rel  state  Q)"
      unfolding wf_eq_minimal
      by simp
    hence " ( x. x  ?Q)  ( stateMin  ?Q.  state. (state, stateMin)  ?rel  state  ?Q)"
      by rule
    with  state. state  ?Q
    have " stateMin  ?Q.  state. (state, stateMin)  ?rel  state  ?Q"
      by simp
    then obtain stateMin
      where "stateMin  ?Q" and " state. (state, stateMin)  ?rel  state  ?Q"
      by auto
    
    from stateMin  ?Q 
    have "(state0, stateMin)  transitionRelation F0 decisionVars"
      by simp
    with ¬ ?thesis
    have "¬ isFinalState stateMin F0 decisionVars"
      by simp
    then obtain state'::State
      where "transition stateMin state' F0 decisionVars"
      unfolding isFinalState_def
      by auto
    have "(state', stateMin)  ?rel"
      using (state0, stateMin)  transitionRelation F0 decisionVars
            ‹transition stateMin state' F0 decisionVars
      by simp
    with  state. (state, stateMin)  ?rel  state  ?Q
    have "state'  ?Q"
      by force
    moreover
    from (state0, stateMin)  transitionRelation F0 decisionVars ‹transition stateMin state' F0 decisionVars
    have "state'  ?Q"
      unfolding transitionRelation_def
      using rtrancl_into_rtrancl[of "state0" "stateMin" "{(stateA, stateB). transition stateA stateB F0 decisionVars}" "state'"]
      by simp
    ultimately
    have False
      by simp
  }
  thus ?thesis
    by auto
qed

text‹Now we prove the final strong termination result which states
that there cannot be infinite chains of transitions. If there is an
infinite transition chain that starts from an initial state, its
elements would for a set that would contain initial state and for
every element of that set there would be another element of that set
that is directly reachable from it. We show that no such set exists.›
corollary noInfiniteTransitionChains:
  fixes F0::Formula and decisionVars::"Variable set"
  assumes "finite decisionVars"
  shows "¬ ( Q::(State set).  state0  Q. isInitialState state0 F0  
                              ( state  Q. ( state'  Q. transition state state' F0 decisionVars))
            )"
proof-
  {
  assume "¬ ?thesis"
  then obtain Q::"State set" and state0::"State"
    where "isInitialState state0 F0" "state0  Q"
          " state  Q. ( state'  Q. transition state state' F0 decisionVars)"
    by auto
  let ?rel = "{(stateB, stateA). (state0, stateA)  transitionRelation F0 decisionVars 
                         transition stateA stateB F0 decisionVars}"
  from ‹finite decisionVars ‹isInitialState state0 F0
  have "wf ?rel"
    using wfTransitionRelation
    by simp
  hence wfmin: "Q x. x  Q 
         (zQ. y. (y, z)  ?rel  y  Q)"
    unfolding wf_eq_minimal 
    by simp
  let ?Q = "{state  Q. (state0, state)  transitionRelation F0 decisionVars}"
  from state0  Q
  have "state0  ?Q"
    unfolding transitionRelation_def
    by simp
  with wfmin
  obtain stateMin::State
    where "stateMin  ?Q" and "y. (y, stateMin)  ?rel  y  ?Q"
    apply (erule_tac x="?Q" in allE)
    by auto

  from stateMin  ?Q
  have "stateMin  Q" "(state0, stateMin)  transitionRelation F0 decisionVars"
    by auto
  with  state  Q. ( state'  Q. transition state state' F0 decisionVars)
  obtain state'::State
    where "state'  Q" "transition stateMin state' F0 decisionVars"
    by auto

  with (state0, stateMin)  transitionRelation F0 decisionVars
  have "(state', stateMin)  ?rel"
    by simp
  with y. (y, stateMin)  ?rel  y  ?Q
  have "state'  ?Q"
    by force
  
  from state'  Q (state0, stateMin)  transitionRelation F0 decisionVars
    ‹transition stateMin state' F0 decisionVars
  have "state'  ?Q"
    unfolding transitionRelation_def
    using rtrancl_into_rtrancl[of "state0" "stateMin" "{(stateA, stateB). transition stateA stateB F0 decisionVars}" "state'"]
    by simp
  with state'  ?Q
  have False
    by simp
  }
  thus ?thesis
    by force
qed

(******************************************************************************)
subsection‹Completeness›
(******************************************************************************)
text‹In this section we will first show that each final state is
either \textit{SAT} or \textit{UNSAT} state.›

lemma finalNonConflictState: 
  fixes state::State and FO :: Formula
  assumes 
  "¬ applicableDecide state decisionVars"
  shows "vars (elements (getM state))  decisionVars"
proof
  fix x :: Variable
  let ?l = "Pos x"
  assume "x  decisionVars"
  hence "var ?l = x" and "var ?l  decisionVars" and "var (opposite ?l)  decisionVars"
    by auto
  with ¬ applicableDecide state decisionVars 
  have "literalTrue ?l (elements (getM state))  literalFalse ?l (elements (getM state))"
    unfolding applicableDecideCharacterization
    by force
  with ‹var ?l = x
  show "x  vars (elements (getM state))"
    using valuationContainsItsLiteralsVariable[of "?l" "elements (getM state)"]
    using valuationContainsItsLiteralsVariable[of "opposite ?l" "elements (getM state)"]
    by auto
qed


lemma finalConflictingState: 
  fixes state :: State
  assumes 
  "¬ applicableBacktrack state F0" and
  "formulaFalse F0 (elements (getM state))"  
  shows
  "decisions (getM state) = []"
using assms
using applicableBacktrackCharacterization
by auto

lemma finalStateCharacterizationLemma:
  fixes state :: State
  assumes 
  "¬ applicableDecide state decisionVars"  and
  "¬ applicableBacktrack state F0"
  shows
  "(¬ formulaFalse F0 (elements (getM state))  vars (elements (getM state))  decisionVars)  
   (formulaFalse F0 (elements (getM state))  decisions (getM state) = [])"
proof (cases "formulaFalse F0 (elements (getM state))")
  case True
  hence "decisions (getM state) = []"
    using assms
    using finalConflictingState
    by auto
  with True 
  show ?thesis
    by simp
next
  case False
  hence  "vars (elements (getM state))  decisionVars"
    using assms
    using finalNonConflictState
    by auto
  with False
  show ?thesis
    by simp
qed


(*----------------------------------------------------------------------------*)
theorem finalStateCharacterization:
  fixes F0 :: Formula and decisionVars :: "Variable set" and state0 :: State and state :: State
  assumes 
  "isInitialState state0 F0" and
  "(state0, state)  transitionRelation F0 decisionVars" and
  "isFinalState state F0 decisionVars"
  shows 
  "(¬ formulaFalse F0 (elements (getM state))  vars (elements (getM state))  decisionVars)  
   (formulaFalse F0 (elements (getM state))  decisions (getM state) = [])"
(*----------------------------------------------------------------------------*)
proof-
  from ‹isFinalState state F0 decisionVars 
  have **: 
    "¬ applicableBacktrack state F0"
    "¬ applicableDecide state decisionVars"
    unfolding finalStateNonApplicable
    by auto

  thus ?thesis
    using finalStateCharacterizationLemma[of "state" "decisionVars"]
    by simp
qed

text‹Completeness theorems are easy consequences of this characterization and 
 soundness.›
(*----------------------------------------------------------------------------*)
theorem completenessForSAT: 
  fixes F0 :: Formula and decisionVars :: "Variable set" and state0 :: State and state :: State
  assumes 
  "satisfiable F0" and

  "isInitialState state0 F0" and
  "(state0, state)  transitionRelation F0 decisionVars" and
  "isFinalState state F0 decisionVars"

  shows "¬ formulaFalse F0 (elements (getM state))  vars (elements (getM state))  decisionVars"
(*----------------------------------------------------------------------------*)
proof-
  from assms
  have *: "(¬ formulaFalse F0 (elements (getM state))  vars (elements (getM state))  decisionVars)  
    (formulaFalse F0 (elements (getM state))  decisions (getM state) = [])"
    using finalStateCharacterization[of "state0" "F0" "state" "decisionVars"]
    by auto
  {
    assume "formulaFalse F0 (elements (getM state))"
    with * 
    have "formulaFalse F0 (elements (getM state))" "decisions (getM state) = []"
      by auto
    with assms
      have "¬ satisfiable F0"
      using soundnessForUNSAT
      by simp
    with ‹satisfiable F0
    have False
      by simp
  }
  with * show ?thesis
    by auto
qed

(*----------------------------------------------------------------------------*)
theorem completenessForUNSAT: 
  fixes F0 :: Formula and decisionVars :: "Variable set" and state0 :: State and state :: State
  assumes 
  "vars F0  decisionVars" and
  "¬ satisfiable F0" and

  "isInitialState state0 F0" and
  "(state0, state)  transitionRelation F0 decisionVars" and
  "isFinalState state F0 decisionVars"

  shows 
  "formulaFalse F0 (elements (getM state))  decisions (getM state) = []"
(*----------------------------------------------------------------------------*)
proof-
  from assms
  have *: 
  "(¬ formulaFalse F0 (elements (getM state))  vars (elements (getM state))  decisionVars)  
   (formulaFalse F0 (elements (getM state))   decisions (getM state) = [])"
    using finalStateCharacterization[of "state0" "F0" "state" "decisionVars"]
    by auto
  {
    assume "¬ formulaFalse F0 (elements (getM state))"
    with *
    have "¬ formulaFalse F0 (elements (getM state))" "vars (elements (getM state))  decisionVars"
      by auto
    with assms
    have "satisfiable F0"
      using soundnessForSAT[of "F0" "decisionVars" "state0" "state"]
      unfolding satisfiable_def
      by auto
    with ¬ satisfiable F0
    have False
      by simp
  }
  with * show ?thesis
    by auto
qed

(*----------------------------------------------------------------------------*)
theorem partialCorrectness: 
  fixes F0 :: Formula and decisionVars :: "Variable set" and state0 :: State and state :: State
  assumes 
  "vars F0  decisionVars" and  

  "isInitialState state0 F0" and
  "(state0, state)  transitionRelation F0 decisionVars" and
  "isFinalState state F0 decisionVars"

  shows 
  "satisfiable F0 = (¬ formulaFalse F0 (elements (getM state)))"
(*----------------------------------------------------------------------------*)
using assms
using completenessForUNSAT[of "F0" "decisionVars" "state0" "state"]
using completenessForSAT[of "F0" "state0" "state" "decisionVars"]
by auto

end

Theory NieuwenhuisOliverasTinelli

(*    Title:              SatSolverVerification/NieuwenhuisOliverasTinelli.thy
      Author:             Filip Maric
      Maintainer:         Filip Maric <filip at matf.bg.ac.yu>
*)

section‹Transition system of Nieuwenhuis, Oliveras and Tinelli.›
theory NieuwenhuisOliverasTinelli
imports SatSolverVerification
begin

text‹This theory formalizes the transition rule system given by
Nieuwenhuis et al. in \cite{NieuwenhuisOliverasTinelli}›


(******************************************************************************)
subsection‹Specification›
(******************************************************************************)

record State = 
"getF" :: Formula
"getM" :: LiteralTrail

definition
appliedDecide:: "State  State  Variable set  bool"
where
"appliedDecide stateA stateB decisionVars == 
   l. 
        (var l)  decisionVars  
        ¬ l el (elements (getM stateA))  
        ¬ opposite l el (elements (getM stateA)) 

        getF stateB = getF stateA 
        getM stateB = getM stateA @ [(l, True)]
"
definition
applicableDecide :: "State  Variable set  bool"
where
"applicableDecide state decisionVars ==  state'. appliedDecide state state' decisionVars"

definition
appliedUnitPropagate :: "State  State  bool"
where
"appliedUnitPropagate stateA stateB == 
   (uc::Clause) (ul::Literal). 
       uc el (getF stateA)  
       isUnitClause uc ul (elements (getM stateA))  

       getF stateB = getF stateA 
       getM stateB = getM stateA @ [(ul, False)]
"
definition
applicableUnitPropagate :: "State  bool"
where
"applicableUnitPropagate state ==  state'. appliedUnitPropagate state state'"

definition
appliedBackjump :: "State  State  bool"
where
"appliedBackjump stateA stateB == 
   bc bl level. 
       isUnitClause bc bl (elements (prefixToLevel level (getM stateA)))  
       formulaEntailsClause (getF stateA) bc  
       var bl  vars (getF stateA)  vars (elements (getM stateA))  
       0  level  level < (currentLevel (getM stateA)) 

       getF stateB = getF stateA 
       getM stateB = prefixToLevel level (getM stateA) @ [(bl, False)]
"
definition
applicableBackjump :: "State  bool"
where
"applicableBackjump state ==   state'. appliedBackjump state state'"


definition
appliedLearn :: "State  State  bool"
where
"appliedLearn stateA stateB == 
   c. 
       (formulaEntailsClause (getF stateA) c)  
       (vars c)  vars (getF stateA)  vars (elements (getM stateA))  
       getF stateB = getF stateA @ [c] 
       getM stateB = getM stateA
"
definition
applicableLearn :: "State  bool"
where
"applicableLearn state == ( state'. appliedLearn state state')"



text‹Solving starts with the initial formula and the empty trail.›
definition
isInitialState :: "State  Formula  bool"
where
"isInitialState state F0 == 
      getF state = F0 
      getM state = []
"

text‹Transitions are preformed only by using given rules.›
definition
"transition stateA stateB decisionVars == 
     appliedDecide        stateA stateB decisionVars 
     appliedUnitPropagate stateA stateB  
     appliedLearn         stateA stateB 
     appliedBackjump      stateA stateB 
"

text‹Transition relation is obtained by applying transition rules
iteratively. It is defined using a reflexive-transitive closure.›
definition
"transitionRelation decisionVars == ({(stateA, stateB). transition stateA stateB decisionVars})^*"

text‹Final state is one in which no rules apply›
definition
isFinalState :: "State  Variable set  bool"
where
"isFinalState state decisionVars == ¬ ( state'. transition state state' decisionVars)"


text‹The following several lemmas establish conditions for applicability of different rules.›
lemma applicableDecideCharacterization:
  fixes stateA::State
  shows "applicableDecide stateA decisionVars = 
  ( l. 
        (var l)  decisionVars  
        ¬ l el (elements (getM stateA))  
        ¬ opposite l el (elements (getM stateA))) 
  " (is "?lhs = ?rhs")
proof
  assume ?rhs
  then obtain l where 
    *: "(var l)  decisionVars" "¬ l el (elements (getM stateA))" "¬ opposite l el (elements (getM stateA))"
    unfolding applicableDecide_def
    by auto
  let ?stateB = "stateA getM := (getM stateA) @ [(l, True)] "
  from * have "appliedDecide stateA ?stateB decisionVars"
    unfolding appliedDecide_def
    by auto
  thus ?lhs
    unfolding applicableDecide_def
    by auto
next
  assume ?lhs
  then obtain stateB l
    where "(var l)  decisionVars" "¬ l el (elements (getM stateA))"
    "¬ opposite l el (elements (getM stateA))"
    unfolding applicableDecide_def
    unfolding appliedDecide_def
    by auto
  thus ?rhs
    by auto
qed

lemma applicableUnitPropagateCharacterization:
  fixes stateA::State and F0::Formula
  shows "applicableUnitPropagate stateA = 
  ( (uc::Clause) (ul::Literal). 
       uc el (getF stateA)  
       isUnitClause uc ul (elements (getM stateA)))
  " (is "?lhs = ?rhs")
proof
  assume "?rhs"
  then obtain ul uc 
    where *: "uc el (getF stateA)" "isUnitClause uc ul (elements (getM stateA))"
    unfolding applicableUnitPropagate_def
    by auto
  let ?stateB = "stateA getM := getM stateA @ [(ul, False)] "
  from * have "appliedUnitPropagate stateA ?stateB" 
    unfolding appliedUnitPropagate_def
    by auto
  thus ?lhs
    unfolding applicableUnitPropagate_def
    by auto
next
  assume ?lhs
  then obtain stateB uc ul
    where "uc el (getF stateA)" "isUnitClause uc ul (elements (getM stateA))"
    unfolding applicableUnitPropagate_def
    unfolding appliedUnitPropagate_def
    by auto
  thus ?rhs
    by auto
qed

lemma applicableBackjumpCharacterization:
  fixes stateA::State
  shows "applicableBackjump stateA = 
   ( bc bl level. 
      isUnitClause bc bl (elements (prefixToLevel level (getM stateA)))  
      formulaEntailsClause (getF stateA) bc  
      var bl  vars (getF stateA)  vars (elements (getM stateA))  
      0  level  level < (currentLevel (getM stateA)))" (is "?lhs = ?rhs")
proof
  assume "?rhs"
  then obtain bc bl level
    where *: "isUnitClause bc bl (elements (prefixToLevel level (getM stateA)))"
     "formulaEntailsClause (getF stateA) bc"
     "var bl  vars (getF stateA)  vars (elements (getM stateA))"
     "0  level" "level < (currentLevel (getM stateA))"
    unfolding applicableBackjump_def
    by auto
  let ?stateB = "stateA getM := prefixToLevel level (getM stateA) @ [(bl, False)]"
  from * have "appliedBackjump stateA ?stateB"
    unfolding appliedBackjump_def
    by auto
  thus "?lhs"
    unfolding applicableBackjump_def
    by auto
next
  assume "?lhs"
  then obtain stateB 
    where "appliedBackjump stateA stateB"
    unfolding applicableBackjump_def
    by auto
  then obtain bc bl level
    where "isUnitClause bc bl (elements (prefixToLevel level (getM stateA)))"
    "formulaEntailsClause (getF stateA) bc"
    "var bl  vars (getF stateA)  vars (elements (getM stateA))"
    "getF stateB = getF stateA" 
    "getM stateB = prefixToLevel level (getM stateA) @ [(bl, False)]"
     "0  level" "level < (currentLevel (getM stateA))"
    unfolding appliedBackjump_def
    by auto
  thus "?rhs"
    by auto
qed

lemma applicableLearnCharacterization:
  fixes stateA::State
  shows "applicableLearn stateA = 
    ( c. formulaEntailsClause (getF stateA) c  
          vars c  vars (getF stateA)   vars (elements (getM stateA)))" (is "?lhs = ?rhs")
proof
  assume "?rhs"
  then obtain c where
  *: "formulaEntailsClause (getF stateA) c" 
     "vars c  vars (getF stateA)   vars (elements (getM stateA))"
    unfolding applicableLearn_def
    by auto
  let ?stateB = "stateA getF := getF stateA @ [c]"
  from * have "appliedLearn stateA ?stateB"
    unfolding appliedLearn_def
    by auto
  thus "?lhs"
    unfolding applicableLearn_def
    by auto
next
  assume "?lhs"
  then obtain c stateB
    where
    "formulaEntailsClause (getF stateA) c"
    "vars c  vars (getF stateA)  vars (elements (getM stateA))"
    unfolding applicableLearn_def
    unfolding appliedLearn_def
    by auto
  thus "?rhs"
    by auto
qed

text‹Final states are the ones where no rule is applicable.›
lemma finalStateNonApplicable: 
  fixes state::State
  shows "isFinalState state decisionVars = 
          (¬ applicableDecide state decisionVars  
           ¬ applicableUnitPropagate state  
           ¬ applicableBackjump state  
           ¬ applicableLearn state)"
unfolding isFinalState_def
unfolding transition_def
unfolding applicableDecide_def
unfolding applicableUnitPropagate_def
unfolding applicableBackjump_def
unfolding applicableLearn_def
by auto

(******************************************************************************)
subsection‹Invariants›
(******************************************************************************)
text‹Invariants that are relevant for the rest of correctness proof.›
definition
invariantsHoldInState :: "State  Formula  Variable set  bool"
where
"invariantsHoldInState state F0 decisionVars == 
    InvariantImpliedLiterals (getF state) (getM state) 
    InvariantVarsM (getM state) F0 decisionVars 
    InvariantVarsF (getF state) F0 decisionVars 
    InvariantConsistent (getM state) 
    InvariantUniq (getM state)  
    InvariantEquivalent F0 (getF state)
"

text‹Invariants hold in initial states.›
lemma invariantsHoldInInitialState:
  fixes state :: State and F0 :: Formula
  assumes "isInitialState state F0" 
  shows "invariantsHoldInState state F0 decisionVars"
using assms
by (auto simp add:
  isInitialState_def 
  invariantsHoldInState_def 
  InvariantImpliedLiterals_def 
  InvariantVarsM_def
  InvariantVarsF_def
  InvariantConsistent_def
  InvariantUniq_def
  InvariantEquivalent_def equivalentFormulae_def
)

text‹Valid transitions preserve invariants.›
lemma transitionsPreserveInvariants: 
  fixes stateA::State and stateB::State
  assumes "transition stateA stateB decisionVars" and 
  "invariantsHoldInState stateA F0 decisionVars"
  shows "invariantsHoldInState stateB F0 decisionVars"
proof-
    from ‹invariantsHoldInState stateA F0 decisionVars
    have 
      "InvariantImpliedLiterals (getF stateA) (getM stateA)" and 
      "InvariantVarsM (getM stateA) F0 decisionVars" and
      "InvariantVarsF (getF stateA) F0 decisionVars" and
      "InvariantConsistent (getM stateA)" and
      "InvariantUniq (getM stateA)" and
      "InvariantEquivalent F0 (getF stateA)"
      unfolding invariantsHoldInState_def
      by auto
  {
    assume "appliedDecide stateA stateB decisionVars"
    then obtain l::Literal where
      "(var l)  decisionVars"
      "¬ literalTrue l (elements (getM stateA))"
      "¬ literalFalse l (elements (getM stateA))"
      "getM stateB = getM stateA @ [(l, True)]"
      "getF stateB = getF stateA"
      unfolding appliedDecide_def
      by auto

    from ¬ literalTrue l (elements (getM stateA)) ¬ literalFalse l (elements (getM stateA)) 
    have *: "var l  vars (elements (getM stateA))"
      using variableDefinedImpliesLiteralDefined[of "l" "elements (getM stateA)"]
      by simp

    have "InvariantImpliedLiterals (getF stateB) (getM stateB)"
      using ‹getF stateB = getF stateA
        ‹getM stateB = getM stateA @ [(l, True)] 
        ‹InvariantImpliedLiterals (getF stateA) (getM stateA)
        ‹InvariantUniq (getM stateA)
        ‹var l  vars (elements (getM stateA))
        InvariantImpliedLiteralsAfterDecide[of "getF stateA" "getM stateA" "l" "getM stateB"]
      by simp
    moreover
    have "InvariantVarsM (getM stateB) F0 decisionVars"
      using ‹getM stateB = getM stateA @ [(l, True)] 
        ‹InvariantVarsM (getM stateA) F0 decisionVars
        ‹var l  decisionVars
        InvariantVarsMAfterDecide[of "getM stateA" "F0" "decisionVars" "l" "getM stateB"]
      by simp
    moreover 
    have "InvariantVarsF (getF stateB) F0 decisionVars"
      using ‹getF stateB = getF stateA
      ‹InvariantVarsF (getF stateA) F0 decisionVars
      by simp
    moreover
    have "InvariantConsistent (getM stateB)"
      using ‹getM stateB = getM stateA @ [(l, True)] 
        ‹InvariantConsistent (getM stateA)
        ‹var l  vars (elements (getM stateA))
        InvariantConsistentAfterDecide[of "getM stateA" "l" "getM stateB"]
      by simp
    moreover
    have "InvariantUniq (getM stateB)"
      using ‹getM stateB = getM stateA @ [(l, True)] 
        ‹InvariantUniq (getM stateA)
        ‹var l  vars (elements (getM stateA))
        InvariantUniqAfterDecide[of "getM stateA" "l" "getM stateB"]
      by simp
    moreover
    have "InvariantEquivalent F0 (getF stateB)"
      using ‹getF stateB = getF stateA
      ‹InvariantEquivalent F0 (getF stateA)
      by simp
    ultimately
    have ?thesis
      unfolding invariantsHoldInState_def
      by auto
  }
  moreover
  {
    assume "appliedUnitPropagate stateA stateB"
    then obtain uc::Clause and ul::Literal where 
      "uc el (getF stateA)"
      "isUnitClause uc ul (elements (getM stateA))"
      "getF stateB = getF stateA"
      "getM stateB = getM stateA @ [(ul, False)]"
      unfolding appliedUnitPropagate_def
      by auto

    from ‹isUnitClause uc ul (elements (getM stateA))
    have "ul el uc"
      unfolding isUnitClause_def
      by simp

    from uc el (getF stateA)
    have "formulaEntailsClause (getF stateA) uc"
      by (simp add: formulaEntailsItsClauses)

    
    have "InvariantImpliedLiterals (getF stateB) (getM stateB)"
      using ‹getF stateB = getF stateA 
        ‹InvariantImpliedLiterals (getF stateA) (getM stateA) 
        ‹formulaEntailsClause (getF stateA) uc
        ‹isUnitClause uc ul (elements (getM stateA))
        ‹getM stateB = getM stateA @ [(ul, False)]
        InvariantImpliedLiteralsAfterUnitPropagate[of "getF stateA" "getM stateA" "uc" "ul" "getM stateB"]
      by simp
    moreover
    from ul el uc uc el (getF stateA)
    have "ul el (getF stateA)"
      by (auto simp add: literalElFormulaCharacterization)
    with ‹InvariantVarsF (getF stateA) F0 decisionVars
    have "var ul  vars F0  decisionVars"
      using "formulaContainsItsLiteralsVariable" [of "ul" "getF stateA"]
      unfolding InvariantVarsF_def
      by auto

    have "InvariantVarsM (getM stateB) F0 decisionVars"
      using ‹InvariantVarsM (getM stateA) F0 decisionVars
        ‹var ul  vars F0  decisionVars
        ‹getM stateB = getM stateA @ [(ul, False)]
        InvariantVarsMAfterUnitPropagate[of "getM stateA" "F0" "decisionVars" "ul" "getM stateB"]
      by simp
    moreover
    have "InvariantVarsF (getF stateB) F0 decisionVars"
      using ‹getF stateB = getF stateA
      ‹InvariantVarsF (getF stateA) F0 decisionVars
      by simp
    moreover
    have "InvariantConsistent (getM stateB)"
      using ‹InvariantConsistent (getM stateA)
        ‹isUnitClause uc ul (elements (getM stateA))
        ‹getM stateB = getM stateA @ [(ul, False)]
        InvariantConsistentAfterUnitPropagate [of "getM stateA" "uc" "ul" "getM stateB"]
      by simp
    moreover
    have "InvariantUniq (getM stateB)"
      using ‹InvariantUniq (getM stateA)
        ‹isUnitClause uc ul (elements (getM stateA))
        ‹getM stateB = getM stateA @ [(ul, False)]
        InvariantUniqAfterUnitPropagate [of "getM stateA" "uc" "ul" "getM stateB"]
      by simp
    moreover
    have "InvariantEquivalent F0 (getF stateB)"
      using ‹getF stateB = getF stateA 
      ‹InvariantEquivalent F0 (getF stateA)
      by simp
    ultimately
    have ?thesis
      unfolding invariantsHoldInState_def
      by auto
  }
  moreover
  {
    assume "appliedLearn stateA stateB"
    then obtain c::Clause where
      "formulaEntailsClause (getF stateA) c"
      "vars c  vars (getF stateA)  vars (elements (getM stateA))"
      "getF stateB = getF stateA @ [c]"
      "getM stateB = getM stateA"
      unfolding appliedLearn_def
      by auto
    
    have "InvariantImpliedLiterals (getF stateB) (getM stateB)"
      using 
        ‹InvariantImpliedLiterals (getF stateA) (getM stateA)
        ‹getF stateB = getF stateA @ [c]
        ‹getM stateB = getM stateA
        InvariantImpliedLiteralsAfterLearn[of "getF stateA" "getM stateA" "getF stateB"]
      by simp
    moreover
    have "InvariantVarsM (getM stateB) F0 decisionVars"
      using 
        ‹InvariantVarsM (getM stateA) F0 decisionVars
        ‹getM stateB = getM stateA
      by simp
    moreover
    from ‹vars c  vars (getF stateA)  vars (elements (getM stateA))
      ‹InvariantVarsM (getM stateA) F0 decisionVars
        ‹InvariantVarsF (getF stateA) F0 decisionVars
    have "vars c  vars F0  decisionVars"
      unfolding InvariantVarsM_def
      unfolding InvariantVarsF_def
      by auto
    hence "InvariantVarsF (getF stateB) F0 decisionVars"
      using ‹InvariantVarsF (getF stateA) F0 decisionVars
        ‹getF stateB = getF stateA @ [c]
      using varsAppendFormulae [of "getF stateA" "[c]"]
      unfolding InvariantVarsF_def
      by simp
    moreover
    have "InvariantConsistent (getM stateB)"
      using ‹InvariantConsistent (getM stateA)
        ‹getM stateB = getM stateA
      by simp
    moreover
    have "InvariantUniq (getM stateB)"
      using ‹InvariantUniq (getM stateA)
        ‹getM stateB = getM stateA
      by simp
    moreover
    have "InvariantEquivalent F0 (getF stateB)"
      using
        ‹InvariantEquivalent F0 (getF stateA)
        ‹formulaEntailsClause (getF stateA) c
        ‹getF stateB = getF stateA @ [c]
        InvariantEquivalentAfterLearn[of "F0" "getF stateA" "c" "getF stateB"]
      by simp
    ultimately
    have ?thesis
      unfolding invariantsHoldInState_def
      by simp
  }
  moreover
  {
    assume "appliedBackjump stateA stateB"
    then obtain bc::Clause and bl::Literal and level::nat
      where 
      "isUnitClause bc bl (elements (prefixToLevel level (getM stateA)))"
      "formulaEntailsClause (getF stateA) bc"
      "var bl  vars (getF stateA)  vars (elements (getM stateA))"
      "getF stateB = getF stateA"
      "getM stateB = prefixToLevel level (getM stateA) @ [(bl, False)]"
      unfolding appliedBackjump_def
      by auto

    have "isPrefix (prefixToLevel level (getM stateA)) (getM stateA)"
      by (simp add:isPrefixPrefixToLevel)

    have "InvariantImpliedLiterals (getF stateB) (getM stateB)"
      using ‹InvariantImpliedLiterals (getF stateA) (getM stateA)
        ‹isPrefix (prefixToLevel level (getM stateA)) (getM stateA)
        ‹isUnitClause bc bl (elements (prefixToLevel level (getM stateA)))
        ‹formulaEntailsClause (getF stateA) bc
        ‹getF stateB = getF stateA
        ‹getM stateB = prefixToLevel level (getM stateA) @ [(bl, False)]
        InvariantImpliedLiteralsAfterBackjump[of "getF stateA" "getM stateA" "prefixToLevel level (getM stateA)" "bc" "bl" "getM stateB"]
      by simp
    moreover

    from ‹InvariantVarsF (getF stateA) F0 decisionVars
      ‹InvariantVarsM (getM stateA) F0 decisionVars
      ‹var bl  vars (getF stateA)  vars (elements (getM stateA))
    have "var bl  vars F0  decisionVars"
      unfolding InvariantVarsM_def
      unfolding InvariantVarsF_def
      by auto

    have "InvariantVarsM (getM stateB) F0 decisionVars"
      using ‹InvariantVarsM (getM stateA) F0 decisionVars
        ‹isPrefix (prefixToLevel level (getM stateA)) (getM stateA)
        ‹getM stateB = prefixToLevel level (getM stateA) @ [(bl, False)]
        ‹var bl  vars F0  decisionVars
        InvariantVarsMAfterBackjump[of "getM stateA" "F0" "decisionVars" "prefixToLevel level (getM stateA)" "bl" "getM stateB"]
      by simp
    moreover
    have "InvariantVarsF (getF stateB) F0 decisionVars"
      using ‹getF stateB = getF stateA
      ‹InvariantVarsF (getF stateA) F0 decisionVars
      by simp
    moreover    
    have "InvariantConsistent (getM stateB)"
      using ‹InvariantConsistent (getM stateA)
        ‹isPrefix (prefixToLevel level (getM stateA)) (getM stateA)
        ‹isUnitClause bc bl (elements (prefixToLevel level (getM stateA)))
        ‹getM stateB = prefixToLevel level (getM stateA) @ [(bl, False)]
        InvariantConsistentAfterBackjump[of "getM stateA" "prefixToLevel level (getM stateA)" "bc" "bl" "getM stateB"]
      by simp
    moreover
    have "InvariantUniq (getM stateB)"
      using ‹InvariantUniq (getM stateA)
        ‹isPrefix (prefixToLevel level (getM stateA)) (getM stateA)
        ‹isUnitClause bc bl (elements (prefixToLevel level (getM stateA)))
        ‹getM stateB = prefixToLevel level (getM stateA) @ [(bl, False)]
        InvariantUniqAfterBackjump[of "getM stateA" "prefixToLevel level (getM stateA)" "bc" "bl" "getM stateB"]
      by simp
    moreover
    have "InvariantEquivalent F0 (getF stateB)"
      using
      ‹InvariantEquivalent F0 (getF stateA)
      ‹getF stateB = getF stateA
      by simp
    ultimately
    have ?thesis
      unfolding invariantsHoldInState_def
      by auto
  }
  ultimately
  show ?thesis
    using ‹transition stateA stateB decisionVars
    unfolding transition_def
    by auto
qed

text‹The consequence is that invariants hold in all valid runs.›
lemma invariantsHoldInValidRuns: 
  fixes F0 :: Formula and decisionVars :: "Variable set"
  assumes "invariantsHoldInState stateA F0 decisionVars" and
  "(stateA, stateB)  transitionRelation decisionVars"
  shows "invariantsHoldInState stateB F0 decisionVars"
using assms
using transitionsPreserveInvariants
using rtrancl_induct[of "stateA" "stateB" 
  "{(stateA, stateB). transition stateA stateB decisionVars}" "λ x. invariantsHoldInState x F0 decisionVars"]
unfolding transitionRelation_def
by auto

lemma invariantsHoldInValidRunsFromInitialState:
  fixes F0 :: Formula and decisionVars :: "Variable set"
  assumes "isInitialState state0 F0" 
  and "(state0, state)  transitionRelation decisionVars"
  shows "invariantsHoldInState state F0 decisionVars"
proof-
  from ‹isInitialState state0 F0
  have "invariantsHoldInState state0 F0 decisionVars"
    by (simp add:invariantsHoldInInitialState)
  with assms
  show ?thesis
    using invariantsHoldInValidRuns [of "state0"  "F0" "decisionVars" "state"]
    by simp
qed

text‹
 In the following text we will show that there are two kinds of states:
 \begin{enumerate}
  \item \textit{UNSAT} states where @{term "formulaFalse F0 (elements (getM state))"}
  and @{term "decisions (getM state) = []"}. 
  \item \textit{SAT} states where @{term "¬ formulaFalse F0 (elements (getM state))"}
  and @{term "vars (elements (getM state))  decisionVars"}
 \end{enumerate}
  
 The soundness theorems claim that if \textit{UNSAT} state is reached
 the formula is unsatisfiable and if \textit{SAT} state is reached,
 the formula is satisfiable.

 Completeness theorems claim that every final state is either
 \textit{UNSAT} or \textit{SAT}. A consequence of this and soundness
 theorems, is that if formula is unsatisfiable the solver will finish
 in an \textit{UNSAT} state, and if the formula is satisfiable the
 solver will finish in a \textit{SAT} state.›


(******************************************************************************)
subsection‹Soundness›
(******************************************************************************)
(*----------------------------------------------------------------------------*)
theorem soundnessForUNSAT:
  fixes F0 :: Formula and decisionVars :: "Variable set" and state0 :: State and state :: State
  assumes
  "isInitialState state0 F0" and
  "(state0, state)  transitionRelation decisionVars"

  "formulaFalse (getF state) (elements (getM state))"
  "decisions (getM state) = []"

  shows "¬ satisfiable F0"
(*----------------------------------------------------------------------------*)
proof-
  from ‹isInitialState state0 F0 (state0, state)  transitionRelation decisionVars
  have "invariantsHoldInState state F0 decisionVars" 
    using invariantsHoldInValidRunsFromInitialState
    by simp
  hence "InvariantImpliedLiterals (getF state) (getM state)" "InvariantEquivalent F0 (getF state)"
    unfolding invariantsHoldInState_def
    by auto
  with ‹formulaFalse (getF state) (elements (getM state))
    ‹decisions (getM state) = []
  show ?thesis
    using unsatReport[of "getF state" "getM state" "F0"]
    by simp
qed

(*----------------------------------------------------------------------------*)
theorem soundnessForSAT:
  fixes F0 :: Formula and decisionVars :: "Variable set" and state0 :: State and state :: State
  assumes 
  "vars F0  decisionVars" and

  "isInitialState state0 F0" and
  "(state0, state)  transitionRelation decisionVars"

  "¬ formulaFalse (getF state) (elements (getM state))"
  "vars (elements (getM state))  decisionVars"  
  shows 
  "model (elements (getM state)) F0"
(*----------------------------------------------------------------------------*)
proof-
  from ‹isInitialState state0 F0 (state0, state)  transitionRelation decisionVars
  have "invariantsHoldInState state F0 decisionVars" 
    using invariantsHoldInValidRunsFromInitialState
    by simp
  hence 
    "InvariantConsistent (getM state)" 
    "InvariantEquivalent F0 (getF state)"
    "InvariantVarsF (getF state) F0 decisionVars"
    unfolding invariantsHoldInState_def
    by auto
  with assms
  show ?thesis
  using satReport[of "F0" "decisionVars" "getF state" "getM state"]
  by simp
qed


(******************************************************************************)
subsection‹Termination›
(******************************************************************************)
text‹This system is terminating, but only under assumption that
there is no infinite derivation consisting only of applications of 
rule $Learn$. We will formalize this condition by requiring that there
there exists an ordering @{term learnL} on the formulae that is
well-founded such that the state is decreased with each application
of the $Learn$ rule. If such ordering exists, the termination
ordering is built as a lexicographic combination of @{term lexLessRestricted} 
trail ordering and the @{term learnL} ordering. 
›

definition "lexLessState F0 decisionVars == {((stateA::State), (stateB::State)). 
                       (getM stateA, getM stateB)  lexLessRestricted (vars F0  decisionVars)}" 
definition "learnLessState learnL == {((stateA::State), (stateB::State)). 
                        getM stateA = getM stateB  (getF stateA, getF stateB)  learnL}" 
definition "terminationLess F0 decisionVars learnL == 
  {((stateA::State), (stateB::State)). 
      (stateA,stateB)  lexLessState F0 decisionVars  
      (stateA,stateB)  learnLessState learnL}"

text‹We want to show that every valid transition decreases a state
  with respect to the constructed termination ordering. Therefore, we
  show that $Decide$, $UnitPropagate$ and $Backjump$ rule decrease the
  trail with respect to the restricted trail ordering @{term
  lexLessRestricted}.  Invariants ensure that trails are indeed uniq,
  consistent and with finite variable sets. By assumption, $Learn$
  rule will decrease the formula component of the state with respect
  to the @{term learnL} ordering.›

lemma trailIsDecreasedByDeciedUnitPropagateAndBackjump:
  fixes stateA::State and stateB::State
  assumes "invariantsHoldInState stateA F0 decisionVars" and
  "appliedDecide stateA stateB decisionVars  appliedUnitPropagate stateA stateB  appliedBackjump stateA stateB"
  shows "(getM stateB, getM stateA)  lexLessRestricted (vars F0  decisionVars)"
proof-
  from ‹appliedDecide stateA stateB decisionVars  appliedUnitPropagate stateA stateB  appliedBackjump stateA stateB
    ‹invariantsHoldInState stateA F0 decisionVars 
  have "invariantsHoldInState stateB F0 decisionVars"
      using transitionsPreserveInvariants
      unfolding transition_def
      by auto
    from ‹invariantsHoldInState stateA F0 decisionVars 
    have *: "uniq (elements (getM stateA))" "consistent (elements (getM stateA))" "vars (elements (getM stateA))  vars F0  decisionVars"
      unfolding invariantsHoldInState_def
      unfolding InvariantVarsM_def
      unfolding InvariantConsistent_def
      unfolding InvariantUniq_def
      by auto
    from ‹invariantsHoldInState stateB F0 decisionVars 
    have **: "uniq (elements (getM stateB))" "consistent (elements (getM stateB))" "vars (elements (getM stateB))  vars F0  decisionVars"
      unfolding invariantsHoldInState_def
      unfolding InvariantVarsM_def
      unfolding InvariantConsistent_def
      unfolding InvariantUniq_def
      by auto
  {
    assume "appliedDecide stateA stateB decisionVars"
    hence "(getM stateB, getM stateA)  lexLess"
      unfolding appliedDecide_def
      by (auto simp add:lexLessAppend)
    with * ** 
    have "((getM stateB), (getM stateA))  lexLessRestricted (vars F0  decisionVars)"
      unfolding lexLessRestricted_def
      by auto
  }
  moreover
  {
    assume "appliedUnitPropagate stateA stateB"
    hence "(getM stateB, getM stateA)  lexLess"
      unfolding appliedUnitPropagate_def
      by (auto simp add:lexLessAppend)
    with * ** 
    have "(getM stateB, getM stateA)  lexLessRestricted (vars F0  decisionVars)"
      unfolding lexLessRestricted_def
      by auto
  }
  moreover
  {
    assume "appliedBackjump stateA stateB"
    then obtain bc::Clause and bl::Literal and level::nat
      where 
      "isUnitClause bc bl (elements (prefixToLevel level (getM stateA)))"
      "formulaEntailsClause (getF stateA) bc"
      "var bl  vars (getF stateA)  vars (elements (getM stateA))"
      "0  level" "level < currentLevel (getM stateA)" 
      "getF stateB = getF stateA"
      "getM stateB = prefixToLevel level (getM stateA) @ [(bl, False)]"
      unfolding appliedBackjump_def
      by auto
    
    with ‹getM stateB = prefixToLevel level (getM stateA) @ [(bl, False)]
    have "(getM stateB, getM stateA)  lexLess"
      by (simp add:lexLessBackjump)
    with * ** 
    have "(getM stateB, getM stateA)  lexLessRestricted (vars F0  decisionVars)"
      unfolding lexLessRestricted_def
      by auto
  }
  ultimately
  show ?thesis
    using assms
    by auto
qed

text‹Now we can show that, under the assumption for $Learn$ rule,
  every rule application decreases a state with respect to the
  constructed termination ordering.›
theorem stateIsDecreasedByValidTransitions:
  fixes stateA::State and stateB::State 
  assumes "invariantsHoldInState stateA F0 decisionVars" and "transition stateA stateB decisionVars"
  "appliedLearn stateA stateB   (getF stateB, getF stateA)  learnL"
  shows "(stateB, stateA)  terminationLess F0 decisionVars learnL"
proof-
  {
    assume "appliedDecide stateA stateB decisionVars  appliedUnitPropagate stateA stateB  appliedBackjump stateA stateB"
    with ‹invariantsHoldInState stateA F0 decisionVars
    have "(getM stateB, getM stateA)  lexLessRestricted (vars F0  decisionVars)"
      using trailIsDecreasedByDeciedUnitPropagateAndBackjump
      by simp
    hence "(stateB, stateA)  lexLessState F0 decisionVars"
      unfolding lexLessState_def
      by simp
    hence "(stateB, stateA)  terminationLess F0 decisionVars learnL"
      unfolding terminationLess_def
      by simp
  }
  moreover
  {
    assume "appliedLearn stateA stateB"
    with ‹appliedLearn stateA stateB  (getF stateB, getF stateA)  learnL
    have "(getF stateB, getF stateA)  learnL"
      by simp
    moreover
    from ‹appliedLearn stateA stateB
    have "(getM stateB) = (getM stateA)"
      unfolding appliedLearn_def
      by auto
   ultimately
   have "(stateB, stateA)  learnLessState learnL" 
      unfolding learnLessState_def
      by simp
    hence "(stateB, stateA)  terminationLess F0 decisionVars learnL"
      unfolding terminationLess_def
      by simp
  }
  ultimately
  show ?thesis
    using ‹transition stateA stateB decisionVars
    unfolding transition_def
    by auto
qed

text‹The minimal states with respect to the termination ordering are
  final i.e., no further transition rules are applicable.›
definition 
"isMinimalState stateMin F0 decisionVars learnL == ( state::State. (state, stateMin)  terminationLess F0 decisionVars learnL)"

lemma minimalStatesAreFinal:
  fixes stateA::State
  assumes *: " (stateA::State) (stateB::State). appliedLearn stateA stateB   (getF stateB, getF stateA)  learnL" and
  "invariantsHoldInState state F0 decisionVars" and "isMinimalState state F0 decisionVars learnL"
  shows "isFinalState state decisionVars"
proof-
  {
    assume "¬ ?thesis"
    then obtain state'::State 
      where "transition state state' decisionVars"
      unfolding isFinalState_def
      by auto
    with ‹invariantsHoldInState state F0 decisionVars *
    have "(state', state)  terminationLess F0 decisionVars learnL"
      using stateIsDecreasedByValidTransitions[of "state" "F0" "decisionVars" "state'" "learnL"]
      unfolding transition_def
      by auto
    with ‹isMinimalState state F0 decisionVars learnL 
    have False
      unfolding isMinimalState_def
      by auto
  }
  thus ?thesis
    by auto
qed

text‹We now prove that termination ordering is well founded. We
start with two auxiliary lemmas.›
lemma wfLexLessState: 
  fixes decisionVars :: "Variable set" and F0 :: "Formula"
  assumes "finite decisionVars"
  shows "wf (lexLessState F0 decisionVars)"
unfolding wf_eq_minimal
proof-
  show "Q state. state  Q  (stateMinQ. state'. (state', stateMin)  lexLessState F0 decisionVars  state'  Q)"
  proof-
    {
      fix Q :: "State set" and state :: State
      assume "state  Q"
      let ?Q1 = "{M::LiteralTrail.  state. state  Q  (getM state) = M}"
      from state  Q
      have "getM state  ?Q1"
        by auto
      from ‹finite decisionVars 
      have "finite (vars F0  decisionVars)"
        using finiteVarsFormula[of "F0"]
        by simp
      hence "wf (lexLessRestricted (vars F0  decisionVars))"
      using  wfLexLessRestricted[of "vars F0  decisionVars"]
      by simp
    with ‹getM state  ?Q1
      obtain Mmin where "Mmin  ?Q1" "M'. (M', Mmin)  lexLessRestricted (vars F0  decisionVars)  M'  ?Q1"
        unfolding wf_eq_minimal
        apply (erule_tac x="?Q1" in allE)
        apply (erule_tac x="getM state" in allE)
        by auto 
      from Mmin  ?Q1 obtain stateMin
        where "stateMin  Q" "(getM stateMin) = Mmin"
        by auto
      have "state'. (state', stateMin)  lexLessState F0 decisionVars  state'  Q"
      proof
        fix state'
        show "(state', stateMin)  lexLessState F0 decisionVars  state'  Q"
        proof
          assume "(state', stateMin)  lexLessState F0 decisionVars"
          hence "(getM state', getM stateMin)  lexLessRestricted (vars F0  decisionVars)"
            unfolding lexLessState_def
            by auto
          from M'. (M', Mmin)  lexLessRestricted (vars F0  decisionVars)  M'  ?Q1
            (getM state', getM stateMin)  lexLessRestricted (vars F0  decisionVars) ‹getM stateMin = Mmin
          have "getM state'  ?Q1"
            by simp
          with ‹getM stateMin = Mmin
          show "state'  Q"
            by auto
        qed
      qed
      with stateMin  Q
      have " stateMin  Q. (state'. (state', stateMin)  lexLessState F0 decisionVars  state'  Q)"
        by auto
    }
    thus ?thesis
      by auto
  qed
qed

lemma wfLearnLessState: 
  assumes "wf learnL"
  shows "wf (learnLessState learnL)"
unfolding wf_eq_minimal
proof-
  show "Q state. state  Q  (stateMinQ. state'. (state', stateMin)  learnLessState learnL  state'  Q)"
  proof-
    {
      fix Q :: "State set" and state :: State
      assume "state  Q"
      let ?M = "(getM state)"
      let ?Q1 = "{f::Formula.  state. state  Q  (getM state) = ?M  (getF state) = f}"
      from state  Q 
      have "getF state  ?Q1"
        by auto            
      with ‹wf learnL
      obtain FMin where "FMin  ?Q1" "F'. (F', FMin)  learnL  F'  ?Q1"
        unfolding wf_eq_minimal
        apply (erule_tac x="?Q1" in allE)
        apply (erule_tac x="getF state" in allE)
        by auto
      from FMin  ?Q1 obtain stateMin
        where "stateMin  Q" "(getM stateMin) = ?M" "getF stateMin = FMin"
        by auto
      have "state'. (state', stateMin)  learnLessState learnL  state'  Q"
      proof
        fix state'
        show "(state', stateMin)  learnLessState learnL  state'  Q"
        proof
          assume "(state', stateMin)  learnLessState learnL"
          with ‹getM stateMin = ?M 
          have "getM state' = getM stateMin" "(getF state', getF stateMin)  learnL"
            unfolding learnLessState_def
            by auto
          from F'. (F', FMin)  learnL  F'  ?Q1 
            (getF state', getF stateMin)  learnL ‹getF stateMin = FMin
          have "getF state'  ?Q1"
            by simp
          with ‹getM state' = getM stateMin ‹getM stateMin = ?M
          show "state'  Q"
            by auto
        qed
      qed
      with stateMin  Q 
      have " stateMin  Q. (state'. (state', stateMin)  learnLessState learnL  state'  Q)"
        by auto
    }
    thus ?thesis
      by auto
  qed
qed

text‹Now we can prove the following key lemma which shows that the
termination ordering is well founded.›
lemma wfTerminationLess:
  fixes F0 :: Formula and decisionVars :: "Variable set"
  assumes "finite decisionVars" "wf learnL"
  shows "wf (terminationLess F0 decisionVars learnL)"
  unfolding wf_eq_minimal
proof-
  show "Q state. state  Q  ( stateMin  Q. state'. (state', stateMin)  terminationLess F0 decisionVars learnL  state'  Q)"
  proof-
    {
      fix Q::"State set"
      fix state::State
      assume "state  Q"
      have "wf (lexLessState F0 decisionVars)"
        using wfLexLessState[of "decisionVars" "F0"]
        using ‹finite decisionVars
        by simp
      with state  Q obtain state0
        where "state0  Q" "state'. (state', state0)  lexLessState F0 decisionVars  state'  Q"
        unfolding wf_eq_minimal
        by auto
      let ?Q0 = "{state. state  Q  (getM state) = (getM state0)}"
      from state0  Q
      have "state0  ?Q0"
        by simp
      from ‹wf learnL 
      have "wf (learnLessState learnL)"
        using wfLearnLessState
        by simp
      with state0  ?Q0 obtain state1
        where "state1  ?Q0" "state'. (state', state1)  learnLessState learnL  state'  ?Q0"
        unfolding wf_eq_minimal
        apply (erule_tac x="?Q0" in allE)
        apply (erule_tac x="state0" in allE)
        by auto
      from state1  ?Q0
      have "state1  Q" "getM state1 = getM state0"
        by auto
      let ?stateMin = state1
      have "state'. (state', ?stateMin)  terminationLess F0 decisionVars learnL  state'  Q"
      proof
        fix state'
        show "(state', ?stateMin)  terminationLess F0 decisionVars learnL  state'  Q"
        proof
          assume "(state', ?stateMin)  terminationLess F0 decisionVars learnL"
          hence 
            "(state', ?stateMin)  lexLessState F0 decisionVars 
            (state', ?stateMin)  learnLessState learnL"
            unfolding terminationLess_def
            by auto
          moreover
          {
            assume "(state', ?stateMin)  lexLessState F0 decisionVars"
            with ‹getM state1 = getM state0
            have "(state', state0)  lexLessState F0 decisionVars"
              unfolding lexLessState_def
              by simp
            with state'. (state', state0)  lexLessState F0 decisionVars  state'  Q
            have "state'  Q"
              by simp
          }
          moreover
          {
            assume "(state', ?stateMin)  learnLessState learnL"
            with state'. (state', state1)  learnLessState learnL  state'  ?Q0
            have "state'  ?Q0"
              by simp
            from (state', state1)  learnLessState learnL ‹getM state1 = getM state0
            have "getM state' = getM state0"
              unfolding learnLessState_def
              by auto
            with state'  ?Q0
            have "state'  Q"
              by simp
          }
          ultimately
          show "state'  Q"
            by auto
        qed
      qed
      with ?stateMin  Q have "( stateMin  Q. state'. (state', stateMin)  terminationLess F0 decisionVars learnL  state'  Q)"
        by auto
    }
    thus ?thesis
      by simp
  qed
qed

text‹Using the termination ordering we show that the transition
 relation is well founded on states reachable from initial state.  The
 assumption for the $Learn$ rule is neccessary.›
(*----------------------------------------------------------------------------*)
theorem wfTransitionRelation:
  fixes decisionVars :: "Variable set" and F0 :: "Formula"
  assumes "finite decisionVars" and "isInitialState state0 F0" and
  *: " learnL::(Formula × Formula) set. 
        wf learnL  
        ( stateA stateB. appliedLearn stateA stateB   (getF stateB, getF stateA)  learnL)"
  shows "wf {(stateB, stateA). 
             (state0, stateA)  transitionRelation decisionVars  (transition stateA stateB decisionVars)}"
(*----------------------------------------------------------------------------*)
proof-
  from * obtain learnL::"(Formula × Formula) set"
    where 
    "wf learnL" and
    **: " stateA stateB. appliedLearn stateA stateB   (getF stateB, getF stateA)  learnL"
    by auto
  let ?rel = "{(stateB, stateA). 
                  (state0, stateA)  transitionRelation decisionVars  (transition stateA stateB decisionVars)}"
  let ?rel'= "terminationLess F0 decisionVars learnL"

  have "x y. (x, y)  ?rel  (x, y)  ?rel'"
  proof-
    {
      fix stateA::State and stateB::State
      assume "(stateB, stateA)  ?rel"
      hence "(stateB, stateA)  ?rel'"
        using ‹isInitialState state0 F0
        using invariantsHoldInValidRunsFromInitialState[of "state0" "F0" "stateA" "decisionVars"]
        using stateIsDecreasedByValidTransitions[of "stateA" "F0" "decisionVars" "stateB"] **
        by simp
    }
    thus ?thesis
      by simp
  qed
  moreover 
  have "wf ?rel'"
    using ‹finite decisionVars ‹wf learnL
    by (rule wfTerminationLess)
  ultimately
  show ?thesis
    using wellFoundedEmbed[of "?rel" "?rel'"]
    by simp
qed

text‹We will now give two corollaries of the previous theorem. First
  is a weak termination result that shows that there is a terminating
  run from every intial state to the final one.›
corollary 
  fixes decisionVars :: "Variable set" and F0 :: "Formula" and state0 :: "State"
  assumes "finite decisionVars" and "isInitialState state0 F0" and
  *: " learnL::(Formula × Formula) set. 
        wf learnL  
        ( stateA stateB. appliedLearn stateA stateB   (getF stateB, getF stateA)  learnL)"
  shows " state. (state0, state)  transitionRelation decisionVars  isFinalState state decisionVars"
proof-
  {
    assume "¬ ?thesis"
    let ?Q = "{state. (state0, state)  transitionRelation decisionVars}"
    let ?rel = "{(stateB, stateA). (state0, stateA)  transitionRelation decisionVars 
                         transition stateA stateB decisionVars}"
    have "state0  ?Q"
      unfolding transitionRelation_def
      by simp
    hence " state. state  ?Q"
      by auto

    from assms 
    have "wf ?rel"
      using wfTransitionRelation[of "decisionVars" "state0" "F0"]
      by auto
    hence " Q. ( x. x  Q)  ( stateMin  Q.  state. (state, stateMin)  ?rel  state  Q)"
      unfolding wf_eq_minimal
      by simp
    hence " ( x. x  ?Q)  ( stateMin  ?Q.  state. (state, stateMin)  ?rel  state  ?Q)"
      by rule
    with  state. state  ?Q
    have " stateMin  ?Q.  state. (state, stateMin)  ?rel  state  ?Q"
      by simp
    then obtain stateMin
      where "stateMin  ?Q" and " state. (state, stateMin)  ?rel  state  ?Q"
      by auto
    
    from stateMin  ?Q 
    have "(state0, stateMin)  transitionRelation decisionVars"
      by simp
    with ¬ ?thesis
    have "¬ isFinalState stateMin decisionVars"
      by simp
    then obtain state'::State
      where "transition stateMin state' decisionVars"
      unfolding isFinalState_def
      by auto
    have "(state', stateMin)  ?rel"
      using (state0, stateMin)  transitionRelation decisionVars
            ‹transition stateMin state' decisionVars
      by simp
    with  state. (state, stateMin)  ?rel  state  ?Q
    have "state'  ?Q"
      by force
    moreover
    from (state0, stateMin)  transitionRelation decisionVars ‹transition stateMin state' decisionVars
    have "state'  ?Q"
      unfolding transitionRelation_def
      using rtrancl_into_rtrancl[of "state0" "stateMin" "{(stateA, stateB). transition stateA stateB decisionVars}" "state'"]
      by simp
    ultimately
    have False
      by simp
  }
  thus ?thesis
    by auto
qed


text‹Now we prove the final strong termination result which states
that there cannot be infinite chains of transitions. If there is an
infinite transition chain that starts from an initial state, its
elements would for a set that would contain initial state and for
every element of that set there would be another element of that set
that is directly reachable from it. We show that no such set exists.›
corollary noInfiniteTransitionChains:
  fixes F0::Formula and decisionVars::"Variable set"
  assumes "finite decisionVars" and
  *: " learnL::(Formula × Formula) set. 
        wf learnL  
        ( stateA stateB. appliedLearn stateA stateB   (getF stateB, getF stateA)  learnL)"
  shows "¬ ( Q::(State set).  state0  Q. isInitialState state0 F0  
                              ( state  Q. ( state'  Q. transition state state' decisionVars))
            )"
proof-
  {
  assume "¬ ?thesis"
  then obtain Q::"State set" and state0::"State"
    where "isInitialState state0 F0" "state0  Q"
          " state  Q. ( state'  Q. transition state state' decisionVars)"
    by auto
  let ?rel = "{(stateB, stateA). (state0, stateA)  transitionRelation decisionVars 
                         transition stateA stateB decisionVars}"
  from ‹finite decisionVars ‹isInitialState state0 F0 *
  have "wf ?rel"
    using wfTransitionRelation
    by simp
  hence wfmin: "Q x. x  Q 
         (zQ. y. (y, z)  ?rel  y  Q)"
    unfolding wf_eq_minimal 
    by simp
  let ?Q = "{state  Q. (state0, state)  transitionRelation decisionVars}"
  from state0  Q
  have "state0  ?Q"
    unfolding transitionRelation_def
    by simp
  with wfmin
  obtain stateMin::State
    where "stateMin  ?Q" and "y. (y, stateMin)  ?rel  y  ?Q"
    apply (erule_tac x="?Q" in allE)
    by auto

  from stateMin  ?Q
  have "stateMin  Q" "(state0, stateMin)  transitionRelation decisionVars"
    by auto
  with  state  Q. ( state'  Q. transition state state' decisionVars)
  obtain state'::State
    where "state'  Q" "transition stateMin state' decisionVars"
    by auto

  with (state0, stateMin)  transitionRelation decisionVars
  have "(state', stateMin)  ?rel"
    by simp
  with y. (y, stateMin)  ?rel  y  ?Q
  have "state'  ?Q"
    by force
  
  from state'  Q (state0, stateMin)  transitionRelation decisionVars
    ‹transition stateMin state' decisionVars
  have "state'  ?Q"
    unfolding transitionRelation_def
    using rtrancl_into_rtrancl[of "state0" "stateMin" "{(stateA, stateB). transition stateA stateB decisionVars}" "state'"]
    by simp
  with state'  ?Q
  have False
    by simp
  }
  thus ?thesis
    by force
qed


(******************************************************************************)
subsection‹Completeness›
(******************************************************************************)

text‹In this section we will first show that each final state is
either \textit{SAT} or \textit{UNSAT} state.›

lemma finalNonConflictState: 
  fixes state::State and FO :: Formula
  assumes 
  "¬ applicableDecide state decisionVars"
  shows "vars (elements (getM state))  decisionVars"
proof
  fix x :: Variable
  let ?l = "Pos x"
  assume "x  decisionVars"
  hence "var ?l = x" and "var ?l  decisionVars" and "var (opposite ?l)  decisionVars"
    by auto
  with ¬ applicableDecide state decisionVars 
  have "literalTrue ?l (elements (getM state))  literalFalse ?l (elements (getM state))"
    unfolding applicableDecideCharacterization
    by force
  with ‹var ?l = x
  show "x  vars (elements (getM state))"
    using valuationContainsItsLiteralsVariable[of "?l" "elements (getM state)"]
    using valuationContainsItsLiteralsVariable[of "opposite ?l" "elements (getM state)"]
    by auto
qed


lemma finalConflictingState: 
  fixes state :: State
  assumes 
  "InvariantUniq (getM state)" and
  "InvariantConsistent (getM state)" and
  "InvariantImpliedLiterals (getF state) (getM state)"
  "¬ applicableBackjump state" and
  "formulaFalse (getF state) (elements (getM state))"  
  shows
  "decisions (getM state) = []"
proof-
  from ‹InvariantUniq (getM state)
  have "uniq (elements (getM state))"
    unfolding InvariantUniq_def
    .
  from ‹InvariantConsistent (getM state)
  have "consistent (elements (getM state))"
    unfolding InvariantConsistent_def
    .

  let ?c = "oppositeLiteralList (decisions (getM state))"
  {
    assume "¬ ?thesis"
    hence "?c  []"
      using oppositeLiteralListNonempty[of "decisions (getM state)"]
      by simp
    moreover
    have "clauseFalse ?c (elements (getM state))"
    proof-
      {
        fix l::Literal
        assume "l el ?c"
        hence "opposite l el decisions (getM state)"
          using literalElListIffOppositeLiteralElOppositeLiteralList [of "l" "?c"]
          by simp
        hence "literalFalse l (elements (getM state))"
          using markedElementsAreElements[of "opposite l" "getM state"]
          by simp
      } 
      thus ?thesis
        using clauseFalseIffAllLiteralsAreFalse[of "?c" "elements (getM state)"]
        by simp
    qed
    moreover
    let ?l = "getLastAssertedLiteral (oppositeLiteralList ?c) (elements (getM state))"
    have "isLastAssertedLiteral ?l (oppositeLiteralList ?c) (elements (getM state))"
      using ‹InvariantUniq (getM state)
      using getLastAssertedLiteralCharacterization[of "?c" "elements (getM state)"]
        ?c  [] ‹clauseFalse ?c (elements (getM state))
      unfolding InvariantUniq_def
      by simp
    moreover
    have " l. l el ?c  (opposite l) el (decisions (getM state))"
    proof-
      {
        fix l::Literal
        assume "l el ?c"
        hence "(opposite l) el (oppositeLiteralList ?c)"
          using literalElListIffOppositeLiteralElOppositeLiteralList[of "l" "?c"]
          by simp
      }
      thus ?thesis
        by simp
    qed
    ultimately
    have " level. (isBackjumpLevel level (opposite ?l) ?c (getM state))"
      using ‹uniq (elements (getM state))
      using allDecisionsThenExistsBackjumpLevel[of "getM state" "?c" "opposite ?l"]
      by simp
    then obtain level::nat
      where "isBackjumpLevel level (opposite ?l) ?c (getM state)"
      by auto
    with ‹consistent (elements (getM state)) ‹uniq (elements (getM state)) ‹clauseFalse ?c (elements (getM state))
    have "isUnitClause ?c (opposite ?l) (elements (prefixToLevel level (getM state)))"
      using isBackjumpLevelEnsuresIsUnitInPrefix[of "getM state" "?c" "level" "opposite ?l"]
      by simp
    moreover
    have "formulaEntailsClause (getF state) ?c"
    proof-
      from ‹clauseFalse ?c (elements (getM state)) ‹consistent (elements (getM state))
      have "¬ clauseTautology ?c"
        using tautologyNotFalse[of "?c" "elements (getM state)"]
        by auto

      from ‹formulaFalse (getF state) (elements (getM state)) ‹InvariantImpliedLiterals (getF state) (getM state)
      have "¬ satisfiable ((getF state) @ val2form (decisions (getM state)))"
        using InvariantImpliedLiteralsAndFormulaFalseThenFormulaAndDecisionsAreNotSatisfiable
        by simp
      hence "¬ satisfiable ((getF state) @ val2form (oppositeLiteralList ?c))"
        by simp
      with ¬ clauseTautology ?c
      show ?thesis
        using unsatisfiableFormulaWithSingleLiteralClauses
        by simp
    qed
    moreover 
    have "var ?l  vars (getF state)  vars (elements (getM state))"
    proof-
      from ‹isLastAssertedLiteral ?l (oppositeLiteralList ?c) (elements (getM state))
      have "?l el (oppositeLiteralList ?c)"
        unfolding isLastAssertedLiteral_def
        by simp
      hence "literalTrue ?l (elements (getM state))"
        by (simp add: markedElementsAreElements)
      hence "var ?l  vars (elements (getM state))"
        using valuationContainsItsLiteralsVariable[of "?l" "elements (getM state)"]
        by simp
      thus ?thesis
        by simp
    qed
    moreover 
    have "0  level" "level < (currentLevel (getM state))"
    proof-
      from ‹isBackjumpLevel level (opposite ?l) ?c (getM state)
      have "0  level" "level < (elementLevel ?l (getM state))"
        unfolding isBackjumpLevel_def
        by auto
      thus "0  level" "level < (currentLevel (getM state))"
        using elementLevelLeqCurrentLevel[of "?l" "getM state"]
        by auto
    qed
    ultimately
    have "applicableBackjump state"
      unfolding applicableBackjumpCharacterization
      by force
    with ¬ applicableBackjump state
    have "False"
      by simp
  }
  thus ?thesis
    by auto
qed

lemma finalStateCharacterizationLemma:
  fixes state :: State
  assumes 
  "InvariantUniq (getM state)" and
  "InvariantConsistent (getM state)" and
  "InvariantImpliedLiterals (getF state) (getM state)"
  "¬ applicableDecide state decisionVars"  and
  "¬ applicableBackjump state"
  shows
  "(¬ formulaFalse (getF state) (elements (getM state))  vars (elements (getM state))  decisionVars)  
   (formulaFalse (getF state) (elements (getM state))  decisions (getM state) = [])"
proof (cases "formulaFalse (getF state) (elements (getM state))")
  case True
  hence "decisions (getM state) = []"
    using assms
    using finalConflictingState
    by auto
  with True 
  show ?thesis
    by simp
next
  case False
  hence  "vars (elements (getM state))  decisionVars"
    using assms
    using finalNonConflictState
    by auto
  with False
  show ?thesis
    by simp
qed

(*----------------------------------------------------------------------------*)
theorem finalStateCharacterization:
  fixes F0 :: Formula and decisionVars :: "Variable set" and state0 :: State and state :: State
  assumes 
  "isInitialState state0 F0" and
  "(state0, state)  transitionRelation decisionVars" and
  "isFinalState state decisionVars"
  shows 
  "(¬ formulaFalse (getF state) (elements (getM state))  vars (elements (getM state))  decisionVars)  
   (formulaFalse (getF state) (elements (getM state))  decisions (getM state) = [])"
(*----------------------------------------------------------------------------*)
proof-
  from ‹isInitialState state0 F0 (state0, state)  transitionRelation decisionVars
  have "invariantsHoldInState state F0 decisionVars"
    using invariantsHoldInValidRunsFromInitialState
    by simp
  hence 
    *: "InvariantUniq (getM state)" 
    "InvariantConsistent (getM state)"
    "InvariantImpliedLiterals (getF state) (getM state)"
    unfolding invariantsHoldInState_def
    by auto

  from ‹isFinalState state decisionVars 
  have **: 
    "¬ applicableBackjump state"
    "¬ applicableDecide state decisionVars"
    unfolding finalStateNonApplicable
    by auto

  from * **
  show ?thesis
    using finalStateCharacterizationLemma[of "state" "decisionVars"]
    by simp
qed

text‹Completeness theorems are easy consequences of this characterization and 
 soundness.›

(*----------------------------------------------------------------------------*)
theorem completenessForSAT: 
  fixes F0 :: Formula and decisionVars :: "Variable set" and state0 :: State and state :: State
  assumes 
  "satisfiable F0" and 

  "isInitialState state0 F0" and
  "(state0, state)  transitionRelation decisionVars" and
  "isFinalState state decisionVars"
  shows "¬ formulaFalse (getF state) (elements (getM state))  vars (elements (getM state))  decisionVars"
(*----------------------------------------------------------------------------*)
proof-
  from assms
  have *: "(¬ formulaFalse (getF state) (elements (getM state))   vars (elements (getM state))  decisionVars)  
    (formulaFalse (getF state) (elements (getM state))  decisions (getM state) = [])"
    using finalStateCharacterization[of "state0" "F0" "state" "decisionVars"]
    by auto
  {
    assume "formulaFalse (getF state) (elements (getM state))"
    with * 
    have "formulaFalse (getF state) (elements (getM state))" "decisions (getM state) = []"
      by auto
    with assms
      have "¬ satisfiable F0"
      using soundnessForUNSAT
      by simp
    with ‹satisfiable F0
    have False
      by simp
  }
  with * show ?thesis
    by auto
qed

(*----------------------------------------------------------------------------*)
theorem completenessForUNSAT: 
  fixes F0 :: Formula and decisionVars :: "Variable set" and state0 :: State and state :: State
  assumes 
  "vars F0  decisionVars" and

  "¬ satisfiable F0" and

  "isInitialState state0 F0" and
  "(state0, state)  transitionRelation decisionVars" and
  "isFinalState state decisionVars"
  shows 
  "formulaFalse (getF state) (elements (getM state))  decisions (getM state) = []"
(*----------------------------------------------------------------------------*)
proof-
  from assms
  have *: 
  "(¬ formulaFalse (getF state) (elements (getM state))  vars (elements (getM state))  decisionVars)  
   (formulaFalse (getF state) (elements (getM state))   decisions (getM state) = [])"
    using finalStateCharacterization[of "state0" "F0" "state" "decisionVars"]
    by auto
  {
    assume "¬ formulaFalse (getF state) (elements (getM state))"
    with *
    have "¬ formulaFalse (getF state) (elements (getM state))" "vars (elements (getM state))  decisionVars"
      by auto
    with assms
    have "satisfiable F0"
      using soundnessForSAT[of "F0" "decisionVars" "state0" "state"]
      unfolding satisfiable_def
      by auto
    with ¬ satisfiable F0
    have False
      by simp
  }
  with * show ?thesis
    by auto
qed

(*----------------------------------------------------------------------------*)
theorem partialCorrectness: 
  fixes F0 :: Formula and decisionVars :: "Variable set" and state0 :: State and state :: State
  assumes 
  "vars F0  decisionVars" and  

  "isInitialState state0 F0" and
  "(state0, state)  transitionRelation decisionVars" and
  "isFinalState state decisionVars"
  shows 
  "satisfiable F0 = (¬ formulaFalse (getF state) (elements (getM state)))"
(*----------------------------------------------------------------------------*)
using assms
using completenessForUNSAT[of "F0" "decisionVars" "state0" "state"]
using completenessForSAT[of "F0" "state0" "state" "decisionVars"]
by auto

end

Theory KrsticGoel

(*    Title:              SatSolverVerification/KrsticGoel.thy
      Author:             Filip Maric
      Maintainer:         Filip Maric <filip at matf.bg.ac.yu>
*)

section‹Transition system of Krsti\' c and Goel.›
theory KrsticGoel
imports SatSolverVerification
begin

text‹This theory formalizes the transition rule system given by
Krsti\' c and Goel in \cite{KrsticGoel}. Some rules of the system are 
generalized a bit, so that the system can model some more general solvers 
(e.g., SMT solvers).›

(******************************************************************************)
subsection‹Specification›
(******************************************************************************)

record State = 
"getF" :: Formula
"getM" :: LiteralTrail
"getConflictFlag" :: bool
"getC" :: Clause

definition
appliedDecide:: "State  State  Variable set  bool"
where
"appliedDecide stateA stateB decisionVars == 
   l. 
        (var l)  decisionVars  
        ¬ l el (elements (getM stateA))  
        ¬ opposite l el (elements (getM stateA)) 

        getF stateB = getF stateA 
        getM stateB = getM stateA @ [(l, True)]  
        getConflictFlag stateB = getConflictFlag stateA 
        getC stateB = getC stateA
"
definition
applicableDecide :: "State  Variable set  bool"
where
"applicableDecide state decisionVars ==  state'. appliedDecide state state' decisionVars"

text‹Notice that the given UnitPropagate description is weaker than
in original \cite{KrsticGoel} paper. Namely, propagation can be done
over a clause that is not a member of the formula, but is entailed by
it. The condition imposed on the variable of the unit literal is
necessary to ensure the termination.›
definition
appliedUnitPropagate :: "State  State  Formula  Variable set  bool"
where
"appliedUnitPropagate stateA stateB F0 decisionVars == 
   (uc::Clause) (ul::Literal). 
        formulaEntailsClause (getF stateA) uc  
        (var ul)  decisionVars  vars F0 
        isUnitClause uc ul (elements (getM stateA))  

       getF stateB = getF stateA 
       getM stateB = getM stateA @ [(ul, False)]  
       getConflictFlag stateB = getConflictFlag stateA 
       getC stateB = getC stateA
"
definition
applicableUnitPropagate :: "State  Formula  Variable set  bool"
where
"applicableUnitPropagate state F0 decisionVars ==  state'. appliedUnitPropagate state state' F0 decisionVars"

text‹Notice, also, that $Conflict$ can be performed for a clause
that is not a member of the formula.›
definition
appliedConflict :: "State  State  bool"
where
"appliedConflict stateA stateB == 
   clause. 
       getConflictFlag stateA = False 
       formulaEntailsClause (getF stateA) clause  
       clauseFalse clause (elements (getM stateA))  

       getF stateB = getF stateA 
       getM stateB = getM stateA  
       getConflictFlag stateB = True  
       getC stateB = clause
  "
definition
applicableConflict :: "State  bool"
where
"applicableConflict state ==  state'. appliedConflict state state'"

text‹Notice, also, that the explanation can be done over a reason clause that is
not a member of the formula, but is only entailed by it.›
definition
appliedExplain :: "State  State  bool"
where
"appliedExplain stateA stateB == 
    l reason. 
       getConflictFlag stateA = True   
       l el getC stateA  
       formulaEntailsClause (getF stateA) reason  
       isReason reason (opposite l) (elements (getM stateA))  

       getF stateB = getF stateA 
       getM stateB = getM stateA  
       getConflictFlag stateB = True 
       getC stateB = resolve (getC stateA) reason l
   "
definition
applicableExplain :: "State  bool"
where
"applicableExplain state ==  state'. appliedExplain state state'"


definition
appliedLearn :: "State  State  bool"
where
"appliedLearn stateA stateB == 
       getConflictFlag stateA = True  
       ¬ getC stateA el getF stateA 

       getF stateB = getF stateA @ [getC stateA] 
       getM stateB = getM stateA  
       getConflictFlag stateB = True 
       getC stateB = getC stateA
"
definition
applicableLearn :: "State  bool"
where
"applicableLearn state ==  state'. appliedLearn state state'"

text‹Since unit propagation can be done over non-member clauses, it is not required that the conflict clause
is learned before the $Backjump$ is applied.›
definition
appliedBackjump :: "State  State  bool"
where
"appliedBackjump stateA stateB == 
   l level. 
       getConflictFlag stateA = True  
       isBackjumpLevel level l (getC stateA) (getM stateA) 

       getF stateB = getF stateA 
       getM stateB = prefixToLevel level (getM stateA) @ [(l, False)] 
       getConflictFlag stateB = False 
       getC stateB = []
  "
definition
applicableBackjump :: "State  bool"
where
"applicableBackjump state ==  state'. appliedBackjump state state'"

text‹Solving starts with the initial formula, the empty trail and in non conflicting state.›
definition
isInitialState :: "State  Formula  bool"
where
"isInitialState state F0 == 
      getF state = F0 
      getM state = [] 
      getConflictFlag state = False 
      getC state = []"

text‹Transitions are preformed only by using given rules.›
definition
transition :: "State  State  Formula  Variable set  bool"
where
"transition stateA stateB F0 decisionVars== 
     appliedDecide        stateA stateB decisionVars  
     appliedUnitPropagate stateA stateB F0 decisionVars  
     appliedConflict      stateA stateB  
     appliedExplain       stateA stateB 
     appliedLearn         stateA stateB 
     appliedBackjump      stateA stateB "

text‹Transition relation is obtained by applying transition rules
iteratively. It is defined using a reflexive-transitive closure.›
definition
"transitionRelation F0 decisionVars == ({(stateA, stateB). transition stateA stateB F0 decisionVars})^*"

text‹Final state is one in which no rules apply›
definition
isFinalState :: "State  Formula  Variable set  bool"
where
"isFinalState state F0 decisionVars == ¬ ( state'. transition state state' F0 decisionVars)"


text‹The following several lemmas establish conditions for applicability of different rules.›
lemma applicableDecideCharacterization:
  fixes stateA::State
  shows "applicableDecide stateA decisionVars = 
  ( l. 
        (var l)  decisionVars  
        ¬ l el (elements (getM stateA))  
        ¬ opposite l el (elements (getM stateA))) 
  " (is "?lhs = ?rhs")
proof
  assume ?rhs
  then obtain l where 
    *: "(var l)  decisionVars" "¬ l el (elements (getM stateA))" "¬ opposite l el (elements (getM stateA))"
    unfolding applicableDecide_def
    by auto
  let ?stateB = "stateA getM := (getM stateA) @ [(l, True)] "
  from * have "appliedDecide stateA ?stateB decisionVars"
    unfolding appliedDecide_def
    by auto
  thus ?lhs
    unfolding applicableDecide_def
    by auto
next
  assume ?lhs
  then obtain stateB l
    where "(var l)  decisionVars" "¬ l el (elements (getM stateA))"
    "¬ opposite l el (elements (getM stateA))"
    unfolding applicableDecide_def
    unfolding appliedDecide_def
    by auto
  thus ?rhs
    by auto
qed

lemma applicableUnitPropagateCharacterization:
  fixes stateA::State and F0::Formula
  shows "applicableUnitPropagate stateA F0 decisionVars = 
  ( (uc::Clause) (ul::Literal). 
        formulaEntailsClause (getF stateA) uc  
        (var ul)  decisionVars  vars F0 
        isUnitClause uc ul (elements (getM stateA)))
  " (is "?lhs = ?rhs")
proof
  assume "?rhs"
  then obtain ul uc 
    where *: 
    "formulaEntailsClause (getF stateA) uc"
    "(var ul)  decisionVars  vars F0"
    "isUnitClause uc ul (elements (getM stateA))"
    unfolding applicableUnitPropagate_def
    by auto
  let ?stateB = "stateA getM := getM stateA @ [(ul, False)] "
  from * have "appliedUnitPropagate stateA ?stateB F0 decisionVars" 
    unfolding appliedUnitPropagate_def
    by auto
  thus ?lhs
    unfolding applicableUnitPropagate_def
    by auto
next
  assume ?lhs
  then obtain stateB uc ul
    where
     "formulaEntailsClause (getF stateA) uc"
    "(var ul)  decisionVars  vars F0"
    "isUnitClause uc ul (elements (getM stateA))"
    unfolding applicableUnitPropagate_def
    unfolding appliedUnitPropagate_def
    by auto
  thus ?rhs
    by auto
qed


lemma applicableBackjumpCharacterization:
  fixes stateA::State
  shows "applicableBackjump stateA = 
     ( l level. 
         getConflictFlag stateA = True  
         isBackjumpLevel level l (getC stateA) (getM stateA)
     )" (is "?lhs = ?rhs")
proof
  assume "?rhs"
  then obtain l level
    where *: 
    "getConflictFlag stateA = True"
    "isBackjumpLevel level l (getC stateA) (getM stateA)"
    unfolding applicableBackjump_def
    by auto
  let ?stateB = "stateA getM := prefixToLevel level (getM stateA) @ [(l, False)], 
                         getConflictFlag := False, 
                         getC := [] "
  from * have "appliedBackjump stateA ?stateB"
    unfolding appliedBackjump_def
    by auto
  thus "?lhs"
    unfolding applicableBackjump_def
    by auto
next
  assume "?lhs"
  then obtain stateB l level
    where  "getConflictFlag stateA = True"
    "isBackjumpLevel level l (getC stateA) (getM stateA)"
    unfolding applicableBackjump_def
    unfolding appliedBackjump_def
    by auto
  thus "?rhs"
    by auto
qed

lemma applicableExplainCharacterization:
  fixes stateA::State
  shows "applicableExplain stateA = 
  ( l reason. 
       getConflictFlag stateA = True   
       l el getC stateA  
       formulaEntailsClause (getF stateA) reason  
       isReason reason (opposite l) (elements (getM stateA))
  )
  " (is "?lhs = ?rhs")
proof
  assume "?rhs"
  then obtain l reason
    where *: 
    "getConflictFlag stateA = True"
    "l el (getC stateA)" "formulaEntailsClause (getF stateA) reason"
    "isReason reason (opposite l) (elements (getM stateA))"
    unfolding applicableExplain_def
    by auto
  let ?stateB = "stateA getC := resolve (getC stateA) reason l "
  from * have "appliedExplain stateA ?stateB"
    unfolding appliedExplain_def
    by auto
  thus "?lhs"
    unfolding applicableExplain_def
    by auto
next
  assume "?lhs"
  then obtain stateB l reason
    where
    "getConflictFlag stateA = True"
    "l el getC stateA" "formulaEntailsClause (getF stateA) reason"
    "isReason reason (opposite l) (elements (getM stateA))"
    unfolding applicableExplain_def
    unfolding appliedExplain_def
    by auto
  thus "?rhs"
    by auto
qed

lemma applicableConflictCharacterization:
  fixes stateA::State
  shows "applicableConflict stateA = 
    ( clause. 
       getConflictFlag stateA = False 
       formulaEntailsClause (getF stateA) clause  
       clauseFalse clause (elements (getM stateA)))" (is "?lhs = ?rhs")
proof
  assume "?rhs"
  then obtain clause
    where *: 
    "getConflictFlag stateA = False" "formulaEntailsClause (getF stateA) clause" "clauseFalse clause (elements (getM stateA))"
    unfolding applicableConflict_def
    by auto
  let ?stateB = "stateA getC := clause, 
                         getConflictFlag := True "
  from * have "appliedConflict stateA ?stateB"
    unfolding appliedConflict_def
    by auto
  thus "?lhs"
    unfolding applicableConflict_def
    by auto
next
  assume "?lhs"
  then obtain stateB clause
    where
    "getConflictFlag stateA = False"
    "formulaEntailsClause (getF stateA) clause"
    "clauseFalse clause (elements (getM stateA))"
    unfolding applicableConflict_def
    unfolding appliedConflict_def
    by auto
  thus "?rhs"
    by auto
qed

lemma applicableLearnCharacterization:
  fixes stateA::State
  shows "applicableLearn stateA = 
           (getConflictFlag stateA = True  
           ¬ getC stateA el getF stateA)" (is "?lhs = ?rhs")
proof
  assume "?rhs"
  hence *: "getConflictFlag stateA = True" "¬ getC stateA el getF stateA"
    unfolding applicableLearn_def
    by auto
  let ?stateB = "stateA getF := getF stateA @ [getC stateA]"
  from * have "appliedLearn stateA ?stateB"
    unfolding appliedLearn_def
    by auto
  thus "?lhs"
    unfolding applicableLearn_def
    by auto
next
  assume "?lhs"
  then obtain stateB
    where
    "getConflictFlag stateA = True" "¬ (getC stateA) el (getF stateA)"
    unfolding applicableLearn_def
    unfolding appliedLearn_def
    by auto
  thus "?rhs"
    by auto
qed

text‹Final states are the ones where no rule is applicable.›
lemma finalStateNonApplicable: 
  fixes state::State
  shows "isFinalState state F0 decisionVars = 
          (¬ applicableDecide state decisionVars  
           ¬ applicableUnitPropagate state F0 decisionVars  
           ¬ applicableBackjump state  
           ¬ applicableLearn state  
           ¬ applicableConflict state  
           ¬ applicableExplain state)"
unfolding isFinalState_def
unfolding transition_def
unfolding applicableDecide_def
unfolding applicableUnitPropagate_def
unfolding applicableBackjump_def
unfolding applicableLearn_def
unfolding applicableConflict_def
unfolding applicableExplain_def
by auto

(******************************************************************************)
subsection‹Invariants›
(******************************************************************************)
text‹Invariants that are relevant for the rest of correctness proof.›
definition
invariantsHoldInState :: "State  Formula  Variable set  bool"
where
"invariantsHoldInState state F0 decisionVars == 
    InvariantVarsM (getM state) F0 decisionVars  
    InvariantVarsF (getF state) F0 decisionVars  
    InvariantConsistent (getM state) 
    InvariantUniq (getM state)  
    InvariantReasonClauses (getF state) (getM state) 
    InvariantEquivalent F0 (getF state) 
    InvariantCFalse (getConflictFlag state) (getM state) (getC state) 
    InvariantCEntailed (getConflictFlag state) (getF state) (getC state)
"

text‹Invariants hold in initial states›
lemma invariantsHoldInInitialState:
  fixes state :: State and F0 :: Formula
  assumes "isInitialState state F0" 
  shows "invariantsHoldInState state F0 decisionVars"
using assms
by (auto simp add:
  isInitialState_def 
  invariantsHoldInState_def 
  InvariantVarsM_def
  InvariantVarsF_def
  InvariantConsistent_def
  InvariantUniq_def
  InvariantReasonClauses_def
  InvariantEquivalent_def equivalentFormulae_def
  InvariantCFalse_def
  InvariantCEntailed_def
)

text‹Valid transitions preserve invariants.›
lemma transitionsPreserveInvariants: 
  fixes stateA::State and stateB::State
  assumes "transition stateA stateB F0 decisionVars" and 
  "invariantsHoldInState stateA F0 decisionVars"
  shows "invariantsHoldInState stateB F0 decisionVars"
proof-
    from ‹invariantsHoldInState stateA F0 decisionVars
    have 
      "InvariantVarsM (getM stateA) F0 decisionVars" and
      "InvariantVarsF (getF stateA) F0 decisionVars" and
      "InvariantConsistent (getM stateA)" and
      "InvariantUniq (getM stateA)" and
      "InvariantReasonClauses (getF stateA) (getM stateA)" and
      "InvariantEquivalent F0 (getF stateA)" and
      "InvariantCFalse (getConflictFlag stateA) (getM stateA) (getC stateA)" and
      "InvariantCEntailed (getConflictFlag stateA) (getF stateA) (getC stateA)"
      unfolding invariantsHoldInState_def
      by auto
  {
    assume "appliedDecide stateA stateB decisionVars"
    then obtain l::Literal where
      "(var l)  decisionVars"
      "¬ literalTrue l (elements (getM stateA))"
      "¬ literalFalse l (elements (getM stateA))"
      "getM stateB = getM stateA @ [(l, True)]"
      "getF stateB = getF stateA"
      "getConflictFlag stateB = getConflictFlag stateA"
      "getC stateB = getC stateA"
      unfolding appliedDecide_def
      by auto

    from ¬ literalTrue l (elements (getM stateA)) ¬ literalFalse l (elements (getM stateA)) 
    have *: "var l  vars (elements (getM stateA))"
      using variableDefinedImpliesLiteralDefined[of "l" "elements (getM stateA)"]
      by simp

    have "InvariantVarsM (getM stateB) F0 decisionVars"
      using ‹getF stateB = getF stateA
        ‹getM stateB = getM stateA @ [(l, True)] 
        ‹InvariantVarsM (getM stateA) F0 decisionVars
        ‹var l  decisionVars
        InvariantVarsMAfterDecide [of "getM stateA" "F0" "decisionVars" "l" "getM stateB"]
      by simp
    moreover
    have "InvariantVarsF (getF stateB) F0 decisionVars"
      using ‹getF stateB = getF stateA
        ‹InvariantVarsF (getF stateA) F0 decisionVars
      by simp
    moreover
    have "InvariantConsistent (getM stateB)"
      using ‹getM stateB = getM stateA @ [(l, True)] 
        ‹InvariantConsistent (getM stateA)
        ‹var l  vars (elements (getM stateA))
        InvariantConsistentAfterDecide[of "getM stateA" "l" "getM stateB"]
      by simp
    moreover
    have "InvariantUniq (getM stateB)"
      using ‹getM stateB = getM stateA @ [(l, True)] 
        ‹InvariantUniq (getM stateA)
        ‹var l  vars (elements (getM stateA))
        InvariantUniqAfterDecide[of "getM stateA" "l" "getM stateB"]
      by simp
    moreover
    have "InvariantReasonClauses (getF stateB) (getM stateB)"
      using ‹getF stateB = getF stateA
        ‹getM stateB = getM stateA @ [(l, True)] 
        ‹InvariantUniq (getM stateA)
        ‹InvariantReasonClauses (getF stateA) (getM stateA)
      using InvariantReasonClausesAfterDecide[of "getF stateA" "getM stateA" "getM stateB" "l"]
      by simp
    moreover
    have "InvariantEquivalent F0 (getF stateB)"
      using ‹getF stateB = getF stateA
      ‹InvariantEquivalent F0 (getF stateA)
      by simp
    moreover
    have "InvariantCFalse (getConflictFlag stateB) (getM stateB) (getC stateB)"
      using ‹getM stateB = getM stateA @ [(l, True)] 
        ‹getConflictFlag stateB = getConflictFlag stateA
        ‹getC stateB = getC stateA
        ‹InvariantCFalse (getConflictFlag stateA) (getM stateA) (getC stateA)
        InvariantCFalseAfterDecide[of "getConflictFlag stateA" "getM stateA" "getC stateA" "getM stateB" "l"]
      by simp
    moreover 
    have "InvariantCEntailed (getConflictFlag stateB) (getF stateB) (getC stateB)"
      using ‹getF stateB = getF stateA
        ‹getConflictFlag stateB = getConflictFlag stateA
        ‹getC stateB = getC stateA
        ‹InvariantCEntailed (getConflictFlag stateA) (getF stateA) (getC stateA)
      by simp
    ultimately
    have ?thesis
      unfolding invariantsHoldInState_def
      by auto
  }
  moreover
  {
    assume "appliedUnitPropagate stateA stateB F0 decisionVars"
    then obtain uc::Clause and ul::Literal where 
      "formulaEntailsClause (getF stateA) uc"
      "(var ul)  decisionVars  vars F0" 
      "isUnitClause uc ul (elements (getM stateA))"
      "getF stateB = getF stateA"
      "getM stateB = getM stateA @ [(ul, False)]"
      "getConflictFlag stateB = getConflictFlag stateA"
      "getC stateB = getC stateA"
      unfolding appliedUnitPropagate_def
      by auto

    from ‹isUnitClause uc ul (elements (getM stateA))
    have "ul el uc"
      unfolding isUnitClause_def
      by simp

    from ‹var ul  decisionVars  vars F0
    have "InvariantVarsM (getM stateB) F0 decisionVars"
      using ‹getF stateB = getF stateA 
        ‹InvariantVarsM (getM stateA) F0 decisionVars
        ‹getM stateB = getM stateA @ [(ul, False)]
        InvariantVarsMAfterUnitPropagate[of "getM stateA" "F0" "decisionVars" "ul" "getM stateB"]
      by auto
    moreover
    have "InvariantVarsF (getF stateB) F0 decisionVars"
      using ‹getF stateB = getF stateA
        ‹InvariantVarsF (getF stateA) F0 decisionVars
      by simp
    moreover
    have "InvariantConsistent (getM stateB)"
      using ‹InvariantConsistent (getM stateA)
        ‹isUnitClause uc ul (elements (getM stateA))
        ‹getM stateB = getM stateA @ [(ul, False)]
        InvariantConsistentAfterUnitPropagate [of "getM stateA" "uc" "ul" "getM stateB"]
      by simp
    moreover
    have "InvariantUniq (getM stateB)"
      using ‹InvariantUniq (getM stateA)
        ‹isUnitClause uc ul (elements (getM stateA))
        ‹getM stateB = getM stateA @ [(ul, False)]
        InvariantUniqAfterUnitPropagate [of "getM stateA" "uc" "ul" "getM stateB"]
      by simp
    moreover
    have "InvariantReasonClauses (getF stateB) (getM stateB)"
      using ‹getF stateB = getF stateA 
        ‹InvariantReasonClauses (getF stateA) (getM stateA)
        ‹isUnitClause uc ul (elements (getM stateA))
        ‹getM stateB = getM stateA @ [(ul, False)]
        ‹formulaEntailsClause (getF stateA) uc
        InvariantReasonClausesAfterUnitPropagate[of "getF stateA" "getM stateA" "uc" "ul" "getM stateB"]
      by simp
    moreover
    have "InvariantEquivalent F0 (getF stateB)"
      using ‹getF stateB = getF stateA 
      ‹InvariantEquivalent F0 (getF stateA)
      by simp
    moreover 
    have "InvariantCFalse (getConflictFlag stateB) (getM stateB) (getC stateB)"
      using ‹getM stateB = getM stateA @ [(ul, False)] 
        ‹getConflictFlag stateB = getConflictFlag stateA
        ‹getC stateB = getC stateA
        ‹InvariantCFalse (getConflictFlag stateA) (getM stateA) (getC stateA)
        InvariantCFalseAfterUnitPropagate[of "getConflictFlag stateA" "getM stateA" "getC stateA" "getM stateB" "ul"]
      by simp
    moreover 
    have "InvariantCEntailed (getConflictFlag stateB) (getF stateB) (getC stateB)"
      using ‹getF stateB = getF stateA 
        ‹getConflictFlag stateB = getConflictFlag stateA
        ‹getC stateB = getC stateA
        ‹InvariantCEntailed (getConflictFlag stateA) (getF stateA) (getC stateA)
      by simp
    ultimately
    have ?thesis
      unfolding invariantsHoldInState_def
      by auto
  }
  moreover
  {
    assume "appliedConflict stateA stateB"
    then obtain clause::Clause where
      "getConflictFlag stateA = False"
      "formulaEntailsClause (getF stateA) clause"
      "clauseFalse clause (elements (getM stateA))"
      "getF stateB = getF stateA"
      "getM stateB = getM stateA"
      "getConflictFlag stateB = True"
      "getC stateB = clause"
    unfolding appliedConflict_def
    by auto
  
    have "InvariantVarsM (getM stateB) F0 decisionVars"
      using ‹InvariantVarsM (getM stateA) F0 decisionVars
        ‹getM stateB = getM stateA
      by simp
    moreover
    have "InvariantVarsF (getF stateB) F0 decisionVars"
      using ‹InvariantVarsF (getF stateA) F0 decisionVars
        ‹getF stateB = getF stateA
      by simp
    moreover
    have "InvariantConsistent (getM stateB)"
      using ‹InvariantConsistent (getM stateA)
        ‹getM stateB = getM stateA
      by simp
    moreover
    have "InvariantUniq (getM stateB)"
      using ‹InvariantUniq (getM stateA)
        ‹getM stateB = getM stateA
      by simp
    moreover
    have "InvariantReasonClauses (getF stateB) (getM stateB)"
      using ‹InvariantReasonClauses (getF stateA) (getM stateA)
        ‹getF stateB = getF stateA
        ‹getM stateB = getM stateA
      by simp
    moreover
    have "InvariantEquivalent F0 (getF stateB)"
      using ‹InvariantEquivalent F0 (getF stateA)
        ‹getF stateB = getF stateA
      by simp
    moreover 
    have "InvariantCFalse (getConflictFlag stateB) (getM stateB) (getC stateB)"
      using
      ‹clauseFalse clause (elements (getM stateA))
      ‹getM stateB = getM stateA
      ‹getConflictFlag stateB = True›
      ‹getC stateB = clause
      unfolding InvariantCFalse_def
      by simp
    moreover 
    have "InvariantCEntailed (getConflictFlag stateB) (getF stateB) (getC stateB)"
      unfolding InvariantCEntailed_def
      using
      ‹getConflictFlag stateB = True›
      ‹formulaEntailsClause (getF stateA) clause
      ‹getF stateB = getF stateA
      ‹getC stateB = clause
      by simp
    ultimately
    have ?thesis
      unfolding invariantsHoldInState_def
      by auto
  }
  moreover
  {
    assume "appliedExplain stateA stateB"
    then obtain l::Literal and reason::Clause where
        "getConflictFlag stateA = True"
        "l el getC stateA"
        "formulaEntailsClause (getF stateA) reason"
        "isReason reason (opposite l) (elements (getM stateA))"
        "getF stateB = getF stateA"
        "getM stateB = getM stateA"
        "getConflictFlag stateB = True"
        "getC stateB = resolve (getC stateA) reason l"
      unfolding appliedExplain_def
      by auto

    have "InvariantVarsM (getM stateB) F0 decisionVars"
      using ‹InvariantVarsM (getM stateA) F0 decisionVars
        ‹getM stateB = getM stateA
      by simp
    moreover
    have "InvariantVarsF (getF stateB) F0 decisionVars"
      using ‹InvariantVarsF (getF stateA) F0 decisionVars
        ‹getF stateB = getF stateA
      by simp
    moreover
    have "InvariantConsistent (getM stateB)"
      using 
        ‹getM stateB = getM stateA
        ‹InvariantConsistent (getM stateA)
      by simp
    moreover
    have "InvariantUniq (getM stateB)"
      using 
        ‹getM stateB = getM stateA
        ‹InvariantUniq (getM stateA)
      by simp
    moreover
    have "InvariantReasonClauses (getF stateB) (getM stateB)"
      using 
        ‹getF stateB = getF stateA
        ‹getM stateB = getM stateA
        ‹InvariantReasonClauses (getF stateA) (getM stateA)
      by simp
    moreover
    have "InvariantEquivalent F0 (getF stateB)"
      using 
        ‹getF stateB = getF stateA
        ‹InvariantEquivalent F0 (getF stateA)
      by simp
    moreover 
    have "InvariantCFalse (getConflictFlag stateB) (getM stateB) (getC stateB)"
      using 
        ‹InvariantCFalse (getConflictFlag stateA) (getM stateA) (getC stateA)
        l el getC stateA
        ‹isReason reason (opposite l) (elements (getM stateA))
        ‹getM stateB = getM stateA
        ‹getC stateB = resolve (getC stateA) reason l
        ‹getConflictFlag stateA = True›
        ‹getConflictFlag stateB = True›
        InvariantCFalseAfterExplain[of "getConflictFlag stateA" "getM stateA" "getC stateA" "opposite l" "reason" "getC stateB"]
      by simp
    moreover 
    have "InvariantCEntailed (getConflictFlag stateB) (getF stateB) (getC stateB)"
      using 
        ‹InvariantCEntailed (getConflictFlag stateA) (getF stateA) (getC stateA)
        l el getC stateA
        ‹isReason reason (opposite l) (elements (getM stateA))
        ‹getF stateB = getF stateA
        ‹getC stateB = resolve (getC stateA) reason l
        ‹getConflictFlag stateA = True›
        ‹getConflictFlag stateB = True›
        ‹formulaEntailsClause (getF stateA) reason
        InvariantCEntailedAfterExplain[of "getConflictFlag stateA" "getF stateA" "getC stateA" "reason" "getC stateB" "opposite l"]
      by simp
    moreover 
    ultimately
    have ?thesis
      unfolding invariantsHoldInState_def
      by auto
  }
  moreover
  {
    assume "appliedLearn stateA stateB"
    hence
      "getConflictFlag stateA = True"
      "¬  getC stateA el getF stateA"
      "getF stateB = getF stateA @ [getC stateA]"
      "getM stateB = getM stateA"
      "getConflictFlag stateB = True"
      "getC stateB = getC stateA"
      unfolding appliedLearn_def
      by auto
    
    from ‹getConflictFlag stateA = True› ‹InvariantCEntailed (getConflictFlag stateA) (getF stateA) (getC stateA) 
    have "formulaEntailsClause (getF stateA) (getC stateA)"
      unfolding InvariantCEntailed_def
      by simp

    have "InvariantVarsM (getM stateB) F0 decisionVars"
      using ‹InvariantVarsM (getM stateA) F0 decisionVars
        ‹getM stateB = getM stateA
      by simp
    moreover
    from ‹InvariantCFalse (getConflictFlag stateA) (getM stateA) (getC stateA) ‹getConflictFlag stateA = True›
    have "clauseFalse (getC stateA) (elements (getM stateA))"
      unfolding InvariantCFalse_def
      by simp
    with ‹InvariantVarsM (getM stateA) F0 decisionVars
    have "(vars (getC stateA))  vars F0  decisionVars"
        unfolding InvariantVarsM_def
        using valuationContainsItsFalseClausesVariables[of "getC stateA" "elements (getM stateA)"]
        by simp
    hence "InvariantVarsF (getF stateB) F0 decisionVars"
      using ‹getF stateB = getF stateA @ [getC stateA]
        ‹InvariantVarsF (getF stateA) F0 decisionVars
        InvariantVarsFAfterLearn [of "getF stateA" "F0" "decisionVars" "getC stateA" "getF stateB"]
      by simp
    moreover
    have "InvariantConsistent (getM stateB)"
      using ‹InvariantConsistent (getM stateA)
        ‹getM stateB = getM stateA
      by simp
    moreover
    have "InvariantUniq (getM stateB)"
      using ‹InvariantUniq (getM stateA)
        ‹getM stateB = getM stateA
      by simp
    moreover
    have "InvariantReasonClauses (getF stateB) (getM stateB)"
      using
        ‹InvariantReasonClauses (getF stateA) (getM stateA)
        ‹formulaEntailsClause (getF stateA) (getC stateA)
        ‹getF stateB = getF stateA @ [getC stateA]
        ‹getM stateB = getM stateA
        InvariantReasonClausesAfterLearn[of "getF stateA" "getM stateA" "getC stateA" "getF stateB"]
      by simp
    moreover
    have "InvariantEquivalent F0 (getF stateB)"
      using
        ‹InvariantEquivalent F0 (getF stateA)
        ‹formulaEntailsClause (getF stateA) (getC stateA)
        ‹getF stateB = getF stateA @ [getC stateA]
        InvariantEquivalentAfterLearn[of "F0" "getF stateA" "getC stateA" "getF stateB"]
      by simp
    moreover 
    have "InvariantCFalse (getConflictFlag stateB) (getM stateB) (getC stateB)"
      using ‹InvariantCFalse (getConflictFlag stateA) (getM stateA) (getC stateA)
        ‹getM stateB = getM stateA
        ‹getConflictFlag stateA = True›
        ‹getConflictFlag stateB = True›
        ‹getM stateB = getM stateA
        ‹getC stateB = getC stateA
      by simp
    moreover 
    have "InvariantCEntailed (getConflictFlag stateB) (getF stateB) (getC stateB)"
      using
        ‹InvariantCEntailed (getConflictFlag stateA) (getF stateA) (getC stateA)
        ‹formulaEntailsClause (getF stateA) (getC stateA)
        ‹getF stateB = getF stateA @ [getC stateA]
        ‹getConflictFlag stateA = True›
        ‹getConflictFlag stateB = True›
        ‹getC stateB = getC stateA
        InvariantCEntailedAfterLearn[of "getConflictFlag stateA" "getF stateA" "getC stateA" "getF stateB"]
      by simp
    ultimately
    have ?thesis
      unfolding invariantsHoldInState_def
      by auto
  }
  moreover
  {
    assume "appliedBackjump stateA stateB"
    then obtain l::Literal and level::nat
      where 
      "getConflictFlag stateA = True"
      "isBackjumpLevel level l (getC stateA) (getM stateA)"
      "getF stateB = getF stateA"
      "getM stateB = prefixToLevel level (getM stateA) @ [(l, False)]"
      "getConflictFlag stateB = False"
      "getC stateB = []"
      unfolding appliedBackjump_def
      by auto
    with ‹InvariantConsistent (getM stateA) ‹InvariantUniq (getM stateA)
      ‹InvariantCFalse (getConflictFlag stateA) (getM stateA) (getC stateA)
    have "isUnitClause (getC stateA) l (elements (prefixToLevel level (getM stateA)))"
      unfolding InvariantUniq_def
      unfolding InvariantConsistent_def
      unfolding InvariantCFalse_def
      using isBackjumpLevelEnsuresIsUnitInPrefix[of "getM stateA" "getC stateA" "level" "l"]
      by simp
    
    from ‹getConflictFlag stateA = True› ‹InvariantCEntailed (getConflictFlag stateA) (getF stateA) (getC stateA)
    have "formulaEntailsClause (getF stateA) (getC stateA)"
      unfolding InvariantCEntailed_def
      by simp

    from ‹isBackjumpLevel level l (getC stateA) (getM stateA)
    have "isLastAssertedLiteral (opposite l) (oppositeLiteralList (getC stateA)) (elements (getM stateA))"
      unfolding isBackjumpLevel_def
      by simp
    hence "l el getC stateA"
      unfolding isLastAssertedLiteral_def
      using literalElListIffOppositeLiteralElOppositeLiteralList[of "l" "getC stateA"]
      by simp

    have "isPrefix (prefixToLevel level (getM stateA)) (getM stateA)"
      by (simp add:isPrefixPrefixToLevel)

    from ‹getConflictFlag stateA = True› ‹InvariantCEntailed (getConflictFlag stateA) (getF stateA) (getC stateA) 
    have "formulaEntailsClause (getF stateA) (getC stateA)"
      unfolding InvariantCEntailed_def
      by simp

    from ‹getConflictFlag stateA = True› ‹InvariantCFalse (getConflictFlag stateA) (getM stateA) (getC stateA) 
    have "clauseFalse (getC stateA) (elements (getM stateA))"
      unfolding InvariantCFalse_def
      by simp
    hence "vars (getC stateA)  vars (elements (getM stateA))"
      using valuationContainsItsFalseClausesVariables[of "getC stateA" "elements (getM stateA)"]
      by simp
    moreover
    from l el getC stateA
    have "var l  vars (getC stateA)"
      using clauseContainsItsLiteralsVariable[of "l" "getC stateA"]
      by simp
    ultimately
    have "var l  vars F0  decisionVars"
      using ‹InvariantVarsM (getM stateA) F0 decisionVars
      unfolding InvariantVarsM_def
      by auto
    
    have "InvariantVarsM (getM stateB) F0 decisionVars"
      using ‹InvariantVarsM (getM stateA) F0 decisionVars
        ‹isUnitClause (getC stateA) l (elements (prefixToLevel level (getM stateA)))
        ‹isPrefix (prefixToLevel level (getM stateA)) (getM stateA)
        ‹var l  vars F0  decisionVars
        ‹formulaEntailsClause (getF stateA) (getC stateA)
        ‹getF stateB = getF stateA
        ‹getM stateB = prefixToLevel level (getM stateA) @ [(l, False)]
        InvariantVarsMAfterBackjump[of "getM stateA" "F0" "decisionVars" "prefixToLevel level (getM stateA)" "l" "getM stateB"]
      by simp
    moreover
    have "InvariantVarsF (getF stateB) F0 decisionVars"
      using ‹InvariantVarsF (getF stateA) F0 decisionVars
        ‹getF stateB = getF stateA
      by simp
    moreover
    have "InvariantConsistent (getM stateB)"
      using ‹InvariantConsistent (getM stateA)
        ‹isUnitClause (getC stateA) l (elements (prefixToLevel level (getM stateA)))
        ‹isPrefix (prefixToLevel level (getM stateA)) (getM stateA)
        ‹getM stateB = prefixToLevel level (getM stateA) @ [(l, False)]
        InvariantConsistentAfterBackjump[of "getM stateA" "prefixToLevel level (getM stateA)" "getC stateA" "l" "getM stateB"]
      by simp
    moreover
    have "InvariantUniq (getM stateB)"
      using ‹InvariantUniq (getM stateA)
        ‹isUnitClause (getC stateA) l (elements (prefixToLevel level (getM stateA)))
        ‹isPrefix (prefixToLevel level (getM stateA)) (getM stateA)
        ‹getM stateB = prefixToLevel level (getM stateA) @ [(l, False)]
        InvariantUniqAfterBackjump[of "getM stateA" "prefixToLevel level (getM stateA)" "getC stateA" "l" "getM stateB"]
      by simp
    moreover
    have "InvariantReasonClauses (getF stateB) (getM stateB)"
      using ‹InvariantUniq (getM stateA) ‹InvariantReasonClauses (getF stateA) (getM stateA)
        ‹isUnitClause (getC stateA) l (elements (prefixToLevel level (getM stateA)))
        ‹isPrefix (prefixToLevel level (getM stateA)) (getM stateA)
        ‹formulaEntailsClause (getF stateA) (getC stateA)
        ‹getF stateB = getF stateA
        ‹getM stateB = prefixToLevel level (getM stateA) @ [(l, False)]
        InvariantReasonClausesAfterBackjump[of "getF stateA" "getM stateA"
        "prefixToLevel level (getM stateA)" "getC stateA"  "l" "getM stateB"]
      by simp
    moreover
    have "InvariantEquivalent F0 (getF stateB)"
      using
      ‹InvariantEquivalent F0 (getF stateA)
      ‹getF stateB = getF stateA
      by simp
    moreover 
    have "InvariantCFalse (getConflictFlag stateB) (getM stateB) (getC stateB)"
      using ‹getConflictFlag stateB = False›
      unfolding InvariantCFalse_def
      by simp
    moreover 
    have "InvariantCEntailed (getConflictFlag stateB) (getF stateB) (getC stateB)"
      using ‹getConflictFlag stateB = False›
      unfolding InvariantCEntailed_def
      by simp
    moreover
    ultimately
    have ?thesis
      unfolding invariantsHoldInState_def
      by auto
  }
  ultimately
  show ?thesis
    using ‹transition stateA stateB F0 decisionVars
    unfolding transition_def
    by auto
qed

text‹The consequence is that invariants hold in all valid runs.›
lemma invariantsHoldInValidRuns: 
  fixes F0 :: Formula and decisionVars :: "Variable set"
  assumes "invariantsHoldInState stateA F0 decisionVars" and
  "(stateA, stateB)  transitionRelation F0 decisionVars"
  shows "invariantsHoldInState stateB F0 decisionVars"
using assms
using transitionsPreserveInvariants
using rtrancl_induct[of "stateA" "stateB" 
  "{(stateA, stateB). transition stateA stateB F0 decisionVars}" "λ x. invariantsHoldInState x F0 decisionVars"]
unfolding transitionRelation_def
by auto

lemma invariantsHoldInValidRunsFromInitialState:
  fixes F0 :: Formula and decisionVars :: "Variable set"
  assumes "isInitialState state0 F0" 
  and "(state0, state)  transitionRelation F0 decisionVars"
  shows "invariantsHoldInState state F0 decisionVars"
proof-
  from ‹isInitialState state0 F0
  have "invariantsHoldInState state0 F0 decisionVars"
    by (simp add:invariantsHoldInInitialState)
  with assms
  show ?thesis
    using invariantsHoldInValidRuns [of "state0"  "F0" "decisionVars" "state"]
    by simp
qed

text‹
 In the following text we will show that there are two kinds of states:
 \begin{enumerate}
  \item \textit{UNSAT} states where @{term "getConflictFlag state = True"}
  and @{term "getC state = []"}. 
  \item \textit{SAT} states where @{term "getConflictFlag state = False"}, 
  @{term "¬ formulaFalse F0 (elements (getM state))"} and 
  @{term "vars (elements (getM state))  decisionVars"}. 
 \end{enumerate}
  
 The soundness theorems claim that if \textit{UNSAT} state is reached
 the formula is unsatisfiable and if \textit{SAT} state is reached,
 the formula is satisfiable.

 Completeness theorems claim that every final state is either
 \textit{UNSAT} or \textit{SAT}. A consequence of this and soundness
 theorems, is that if formula is unsatisfiable the solver will finish
 in an \textit{UNSAT} state, and if the formula is satisfiable the
 solver will finish in a \textit{SAT} state.
›


(******************************************************************************)
subsection‹Soundness›
(******************************************************************************)

theorem soundnessForUNSAT:
  fixes F0 :: Formula and decisionVars :: "Variable set" and state0 :: State and state :: State
  assumes
  "isInitialState state0 F0" and
  "(state0, state)  transitionRelation F0 decisionVars"

  "getConflictFlag state = True" and
  "getC state = []"
  shows "¬ satisfiable F0"
proof-
  from ‹isInitialState state0 F0 (state0, state)  transitionRelation F0 decisionVars
  have "invariantsHoldInState state F0 decisionVars" 
    using invariantsHoldInValidRunsFromInitialState
    by simp
  hence 
    "InvariantEquivalent F0 (getF state)"
    "InvariantCEntailed (getConflictFlag state) (getF state) (getC state)"
    unfolding invariantsHoldInState_def
    by auto
  with ‹getConflictFlag state = True› ‹getC state = []
  show ?thesis
    by (simp add:unsatReportExtensiveExplain)
qed

theorem soundnessForSAT:
  fixes F0 :: Formula and decisionVars :: "Variable set" and state0 :: State and state :: State
  assumes 
  "vars F0  decisionVars" and

  "isInitialState state0 F0" and
  "(state0, state)  transitionRelation F0 decisionVars" and

  "getConflictFlag state = False"
  "¬ formulaFalse (getF state) (elements (getM state))"
  "vars (elements (getM state))  decisionVars"  
  shows 
  "model (elements (getM state)) F0"
proof-
  from ‹isInitialState state0 F0 (state0, state)  transitionRelation F0 decisionVars
  have "invariantsHoldInState state F0 decisionVars" 
    using invariantsHoldInValidRunsFromInitialState
    by simp
  hence 
    "InvariantConsistent (getM state)" 
    "InvariantEquivalent F0 (getF state)"
    "InvariantVarsF (getF state) F0 decisionVars"
    unfolding invariantsHoldInState_def
    by auto
  with assms
  show ?thesis
  using satReport[of "F0" "decisionVars" "getF state" "getM state"]
  by simp
qed



(**************************************************************************)
(*                          T E R M I N A T I O N                         *)
(**************************************************************************)
subsection‹Termination›
text‹We now define a termination ordering which is a lexicographic combination
of @{term lexLessRestricted} trail ordering, @{term boolLess} conflict flag ordering, 
@{term multLess} conflict clause ordering and @{term learnLess} formula ordering. 
This ordering will be central in termination proof.›

definition "lexLessState (F0::Formula) decisionVars == {((stateA::State), (stateB::State)).
  (getM stateA, getM stateB)  lexLessRestricted (vars F0  decisionVars)}"
definition "boolLessState == {((stateA::State), (stateB::State)).
  getM stateA = getM stateB 
  (getConflictFlag stateA, getConflictFlag stateB)  boolLess}"
definition "multLessState == {((stateA::State), (stateB::State)).
  getM stateA = getM stateB 
  getConflictFlag stateA = getConflictFlag stateB 
  (getC stateA, getC stateB)  multLess (getM stateA)}"
definition "learnLessState == {((stateA::State), (stateB::State)).
  getM stateA = getM stateB 
  getConflictFlag stateA = getConflictFlag stateB 
  getC stateA = getC stateB 
  (getF stateA, getF stateB)  learnLess (getC stateA)}"

definition "terminationLess F0 decisionVars == {((stateA::State), (stateB::State)).
  (stateA,stateB)  lexLessState F0 decisionVars 
  (stateA,stateB)  boolLessState   
  (stateA,stateB)  multLessState   
  (stateA,stateB)  learnLessState}"

text‹We want to show that every valid transition decreases a state
  with respect to the constructed termination ordering.›

text‹First we show that $Decide$, $UnitPropagate$ and $Backjump$ rule
decrease the trail with respect to the restricted trail ordering
@{term lexLessRestricted}. Invariants ensure that trails are indeed
uniq, consistent and with finite variable sets.›
lemma trailIsDecreasedByDeciedUnitPropagateAndBackjump:
  fixes stateA::State and stateB::State
  assumes "invariantsHoldInState stateA F0 decisionVars" and
  "appliedDecide stateA stateB decisionVars  appliedUnitPropagate stateA stateB F0 decisionVars  appliedBackjump stateA stateB"
  shows "(getM stateB, getM stateA)  lexLessRestricted (vars F0  decisionVars)"
proof-
  from ‹appliedDecide stateA stateB decisionVars  appliedUnitPropagate stateA stateB F0 decisionVars  appliedBackjump stateA stateB
    ‹invariantsHoldInState stateA F0 decisionVars 
  have "invariantsHoldInState stateB F0 decisionVars"
      using transitionsPreserveInvariants
      unfolding transition_def
      by auto
    from ‹invariantsHoldInState stateA F0 decisionVars 
    have *: "uniq (elements (getM stateA))" "consistent (elements (getM stateA))" "vars (elements (getM stateA))  vars F0  decisionVars"
      unfolding invariantsHoldInState_def
      unfolding InvariantVarsM_def
      unfolding InvariantConsistent_def
      unfolding InvariantUniq_def
      by auto
    from ‹invariantsHoldInState stateB F0 decisionVars 
    have **: "uniq (elements (getM stateB))" "consistent (elements (getM stateB))" "vars (elements (getM stateB))  vars F0  decisionVars"
      unfolding invariantsHoldInState_def
      unfolding InvariantVarsM_def
      unfolding InvariantConsistent_def
      unfolding InvariantUniq_def
      by auto
  {
    assume "appliedDecide stateA stateB decisionVars"
    hence "(getM stateB, getM stateA)  lexLess"
      unfolding appliedDecide_def
      by (auto simp add:lexLessAppend)
    with * ** 
    have "((getM stateB), (getM stateA))  lexLessRestricted (vars F0  decisionVars)"
      unfolding lexLessRestricted_def
      by auto
  }
  moreover
  {
    assume "appliedUnitPropagate stateA stateB F0 decisionVars"
    hence "(getM stateB, getM stateA)  lexLess"
      unfolding appliedUnitPropagate_def
      by (auto simp add:lexLessAppend)
    with * ** 
    have "(getM stateB, getM stateA)  lexLessRestricted (vars F0  decisionVars)"
      unfolding lexLessRestricted_def
      by auto
  }
  moreover
  {
    assume "appliedBackjump stateA stateB"
    then obtain l::Literal and level::nat
      where 
      "getConflictFlag stateA = True"
      "isBackjumpLevel level l (getC stateA) (getM stateA)"
      "getF stateB = getF stateA"
      "getM stateB = prefixToLevel level (getM stateA) @ [(l, False)]"
      "getConflictFlag stateB = False"
      "getC stateB = []"
      unfolding appliedBackjump_def
      by auto
    
    from ‹isBackjumpLevel level l (getC stateA) (getM stateA)
    have "isLastAssertedLiteral (opposite l) (oppositeLiteralList (getC stateA)) (elements (getM stateA))"
      unfolding isBackjumpLevel_def
      by simp
    hence "(opposite l) el elements (getM stateA)"
      unfolding isLastAssertedLiteral_def
      by simp
    hence "elementLevel (opposite l) (getM stateA) <= currentLevel (getM stateA)"
      by (simp add: elementLevelLeqCurrentLevel)
    moreover
    from ‹isBackjumpLevel level l (getC stateA) (getM stateA)
    have "0  level" and "level < elementLevel (opposite l) (getM stateA)" 
      unfolding isBackjumpLevel_def 
      using ‹isLastAssertedLiteral (opposite l) (oppositeLiteralList (getC stateA)) (elements (getM stateA))
      by auto
    ultimately 
    have "level < currentLevel (getM stateA)" 
      by simp
    with 0  level ‹getM stateB = prefixToLevel level (getM stateA) @ [(l, False)]
    have "(getM stateB, getM stateA)  lexLess"
      by (simp add:lexLessBackjump)
    with * ** 
    have "(getM stateB, getM stateA)  lexLessRestricted (vars F0  decisionVars)"
      unfolding lexLessRestricted_def
      by auto
  }
  ultimately
  show ?thesis
    using assms
    by auto
qed

text‹Next we show that $Conflict$ decreases the conflict flag in the @{term boolLess} ordering.›
lemma conflictFlagIsDecreasedByConflict:
  fixes stateA::State and stateB::State
  assumes "appliedConflict stateA stateB"
  shows "getM stateA = getM stateB" and "(getConflictFlag stateB, getConflictFlag stateA)  boolLess"
using assms
unfolding appliedConflict_def
unfolding boolLess_def
by auto

text‹Next we show that $Explain$ decreases the conflict clause with
respect to the @{term multLess} clause ordering.›
lemma conflictClauseIsDecreasedByExplain:
  fixes stateA::State and stateB::State
  assumes "appliedExplain stateA stateB"
  shows 
  "getM stateA = getM stateB" and 
  "getConflictFlag stateA = getConflictFlag stateB" and 
  "(getC stateB, getC stateA)  multLess (getM stateA)"
proof-
  from ‹appliedExplain stateA stateB
  obtain l::Literal and reason::Clause where
    "getConflictFlag stateA = True"
    "l el (getC stateA)"
    "isReason reason (opposite l) (elements (getM stateA))"
    "getF stateB = getF stateA"
    "getM stateB = getM stateA"
    "getConflictFlag stateB = True"
    "getC stateB = resolve (getC stateA) reason l"
    unfolding appliedExplain_def
    by auto
  thus "getM stateA = getM stateB" "getConflictFlag stateA = getConflictFlag stateB" "(getC stateB, getC stateA)  multLess (getM stateA)"
    using multLessResolve[of "opposite l" "getC stateA" "reason" "getM stateA"]
    by auto
qed


text‹Finally, we show that $Learn$ decreases the formula in the @{term learnLess} formula ordering.›
lemma formulaIsDecreasedByLearn:
  fixes stateA::State and stateB::State
  assumes "appliedLearn stateA stateB"
  shows 
  "getM stateA = getM stateB" and 
  "getConflictFlag stateA = getConflictFlag stateB" and 
  "getC stateA = getC stateB" and 
  "(getF stateB, getF stateA)  learnLess (getC stateA)"
proof-
  from ‹appliedLearn stateA stateB
  have
      "getConflictFlag stateA = True"
      "¬ getC stateA el getF stateA"
      "getF stateB = getF stateA @ [getC stateA]"
      "getM stateB = getM stateA"
      "getConflictFlag stateB = True"
      "getC stateB = getC stateA"
    unfolding appliedLearn_def
    by auto
  thus 
    "getM stateA = getM stateB"
    "getConflictFlag stateA = getConflictFlag stateB"
    "getC stateA = getC stateB"
    "(getF stateB, getF stateA)  learnLess (getC stateA)"
    unfolding learnLess_def
    by auto
qed


text‹Now we can prove that every rule application decreases a state
with respect to the constructed termination ordering.›
lemma stateIsDecreasedByValidTransitions:
  fixes stateA::State and stateB::State
  assumes "invariantsHoldInState stateA F0 decisionVars" and "transition stateA stateB F0 decisionVars"
  shows "(stateB, stateA)  terminationLess F0 decisionVars"
proof-
  {
    assume "appliedDecide stateA stateB decisionVars  appliedUnitPropagate stateA stateB F0 decisionVars  appliedBackjump stateA stateB"
    with ‹invariantsHoldInState stateA F0 decisionVars
    have "(getM stateB, getM stateA)  lexLessRestricted (vars F0  decisionVars)"
      using trailIsDecreasedByDeciedUnitPropagateAndBackjump
      by simp
    hence "(stateB, stateA)  lexLessState F0 decisionVars"
      unfolding lexLessState_def
      by simp
    hence "(stateB, stateA)  terminationLess F0 decisionVars"
      unfolding terminationLess_def
      by simp
  }
  moreover
  {
    assume "appliedConflict stateA stateB"
    hence "getM stateA = getM stateB" "(getConflictFlag stateB, getConflictFlag stateA)  boolLess"
      using conflictFlagIsDecreasedByConflict
      by auto
    hence "(stateB, stateA)  boolLessState"
      unfolding boolLessState_def
      by simp
    hence "(stateB, stateA)  terminationLess F0 decisionVars"
      unfolding terminationLess_def
      by simp
  }
  moreover
  {
    assume "appliedExplain stateA stateB"
    hence "getM stateA = getM stateB"
      "getConflictFlag stateA = getConflictFlag stateB"
      "(getC stateB, getC stateA)  multLess (getM stateA)"
      using conflictClauseIsDecreasedByExplain
      by auto
    hence "(stateB, stateA)  multLessState"
      unfolding multLessState_def
      unfolding multLess_def
      by simp
    hence "(stateB, stateA)  terminationLess F0 decisionVars"
      unfolding terminationLess_def
      by simp
  }
  moreover
  {
    assume "appliedLearn stateA stateB"
    hence 
      "getM stateA = getM stateB"
      "getConflictFlag stateA = getConflictFlag stateB"
      "getC stateA = getC stateB"
      "(getF stateB, getF stateA)  learnLess (getC stateA)"
      using formulaIsDecreasedByLearn
      by auto
    hence "(stateB, stateA)  learnLessState"
      unfolding learnLessState_def
      by simp
    hence "(stateB, stateA)  terminationLess F0 decisionVars"
      unfolding terminationLess_def
      by simp
  }
  ultimately
  show ?thesis
    using ‹transition stateA stateB F0 decisionVars
    unfolding transition_def
    by auto
qed

text‹The minimal states with respect to the termination ordering are
  final i.e., no further transition rules are applicable.›
definition 
"isMinimalState stateMin F0 decisionVars == ( state::State. (state, stateMin)  terminationLess F0 decisionVars)"

lemma minimalStatesAreFinal:
  fixes stateA::State
  assumes
  "invariantsHoldInState state F0 decisionVars" and "isMinimalState state F0 decisionVars"
  shows "isFinalState state F0 decisionVars"
proof-
  {
    assume "¬ ?thesis"
    then obtain state'::State 
      where "transition state state' F0 decisionVars"
      unfolding isFinalState_def
      by auto
    with ‹invariantsHoldInState state F0 decisionVars 
    have "(state', state)  terminationLess F0 decisionVars"
      using stateIsDecreasedByValidTransitions[of "state" "F0" "decisionVars" "state'"]
      unfolding transition_def
      by auto
    with ‹isMinimalState state F0 decisionVars 
    have False
      unfolding isMinimalState_def
      by auto
  }
  thus ?thesis
    by auto
qed


text‹We now prove that termination ordering is well founded. We
start with several auxiliary lemmas, one for each component of the termination ordering.›
lemma wfLexLessState: 
  fixes decisionVars :: "Variable set" and F0 :: Formula
  assumes "finite decisionVars"
  shows "wf (lexLessState F0 decisionVars)"
unfolding wf_eq_minimal
proof-
  show "Q state. state  Q  (stateMinQ. state'. (state', stateMin)  lexLessState F0 decisionVars  state'  Q)"
  proof-
    {
      fix Q :: "State set" and state :: State
      assume "state  Q"
      let ?Q1 = "{M::LiteralTrail.  state. state  Q  (getM state) = M}"
      from state  Q
      have "getM state  ?Q1"
        by auto
      from ‹finite decisionVars 
      have "finite (vars F0  decisionVars)"
        using finiteVarsFormula[of "F0"]
        by simp
      hence "wf (lexLessRestricted (vars F0  decisionVars))"
      using  wfLexLessRestricted[of "vars F0  decisionVars"]
      by simp
    with ‹getM state  ?Q1
      obtain Mmin where "Mmin  ?Q1" "M'. (M', Mmin)  lexLessRestricted (vars F0  decisionVars)  M'  ?Q1"
        unfolding wf_eq_minimal
        apply (erule_tac x="?Q1" in allE)
        apply (erule_tac x="getM state" in allE)
        by auto 
      from Mmin  ?Q1 obtain stateMin
        where "stateMin  Q" "(getM stateMin) = Mmin"
        by auto
      have "state'. (state', stateMin)  lexLessState F0 decisionVars  state'  Q"
      proof
        fix state'
        show "(state', stateMin)  lexLessState F0 decisionVars  state'  Q"
        proof
          assume "(state', stateMin)  lexLessState F0 decisionVars"
          hence "(getM state', getM stateMin)  lexLessRestricted (vars F0  decisionVars)"
            unfolding lexLessState_def
            by auto
          from M'. (M', Mmin)  lexLessRestricted (vars F0   decisionVars)  M'  ?Q1
            (getM state', getM stateMin)  lexLessRestricted (vars F0  decisionVars) ‹getM stateMin = Mmin
          have "getM state'  ?Q1"
            by simp
          with ‹getM stateMin = Mmin
          show "state'  Q"
            by auto
        qed
      qed
      with stateMin  Q
      have " stateMin  Q. (state'. (state', stateMin)  lexLessState F0 decisionVars  state'  Q)"
        by auto
    }
    thus ?thesis
      by auto
  qed
qed
     
lemma wfBoolLessState: 
  shows "wf boolLessState"
unfolding wf_eq_minimal
proof-
  show "Q state. state  Q  (stateMinQ. state'. (state', stateMin)  boolLessState  state'  Q)"
  proof-
    {
      fix Q :: "State set" and state :: State
      assume "state  Q"
      let ?M = "(getM state)"
      let ?Q1 = "{b::bool.  state. state  Q  (getM state) = ?M  (getConflictFlag state) = b}"
      from state  Q 
      have "getConflictFlag state  ?Q1"
        by auto
      with wfBoolLess
      obtain bMin where "bMin  ?Q1" "b'. (b', bMin)  boolLess  b'  ?Q1"
        unfolding wf_eq_minimal
        apply (erule_tac x="?Q1" in allE)
        apply (erule_tac x="getConflictFlag state" in allE)
        by auto
      from bMin  ?Q1 obtain stateMin
        where "stateMin  Q" "(getM stateMin) = ?M" "getConflictFlag stateMin = bMin"
        by auto
      have "state'. (state', stateMin)  boolLessState  state'  Q"
      proof
        fix state'
        show "(state', stateMin)  boolLessState  state'  Q"
        proof
          assume "(state', stateMin)  boolLessState"
          with ‹getM stateMin = ?M 
          have "getM state' = getM stateMin" "(getConflictFlag state', getConflictFlag stateMin)  boolLess"
            unfolding boolLessState_def
            by auto
          from b'. (b', bMin)  boolLess  b'  ?Q1 
            (getConflictFlag state', getConflictFlag stateMin)  boolLess› ‹getConflictFlag stateMin = bMin
          have "getConflictFlag state'  ?Q1"
            by simp
          with ‹getM state' = getM stateMin ‹getM stateMin = ?M
          show "state'  Q"
            by auto
        qed
      qed
      with stateMin  Q 
      have " stateMin  Q. (state'. (state', stateMin)  boolLessState  state'  Q)"
        by auto
    }
    thus ?thesis
      by auto
  qed
qed

lemma wfMultLessState:
  shows "wf multLessState"
  unfolding wf_eq_minimal
proof-
  show "Q state. state  Q  ( stateMin  Q. state'. (state', stateMin)  multLessState  state'  Q)"
  proof-
    {
      fix Q :: "State set" and state :: State
      assume "state  Q"
      let ?M = "(getM state)"
      let ?Q1 = "{C::Clause.  state. state  Q  (getM state) = ?M  (getC state) = C}"
      from state  Q 
      have "getC state  ?Q1"
        by auto   
      with wfMultLess[of "?M"]
      obtain Cmin where "Cmin  ?Q1" "C'. (C', Cmin)  multLess ?M  C'  ?Q1"
        unfolding wf_eq_minimal
        apply (erule_tac x="?Q1" in allE)
        apply (erule_tac x="getC state" in allE)
        by auto
      from Cmin  ?Q1 obtain stateMin
        where "stateMin  Q" "(getM stateMin) = ?M" "getC stateMin = Cmin"
        by auto
      have "state'. (state', stateMin)  multLessState  state'  Q"
      proof
        fix state'
        show "(state', stateMin)  multLessState  state'  Q"
        proof
          assume "(state', stateMin)  multLessState"
          with ‹getM stateMin = ?M
          have "getM state' = getM stateMin" "(getC state', getC stateMin)  multLess ?M"
            unfolding multLessState_def
            by auto
          from C'. (C', Cmin)  multLess ?M  C'  ?Q1
            (getC state', getC stateMin)  multLess ?M ‹getC stateMin = Cmin
          have "getC state'  ?Q1"
            by simp
          with ‹getM state' = getM stateMin ‹getM stateMin = ?M
          show "state'  Q"
            by auto
        qed
      qed
      with stateMin  Q 
      have " stateMin  Q. (state'. (state', stateMin)  multLessState  state'  Q)"
        by auto
    }
    thus ?thesis
      by auto
  qed
qed

lemma wfLearnLessState:
  shows "wf learnLessState"
  unfolding wf_eq_minimal
proof-
  show "Q state. state  Q  ( stateMin  Q. state'. (state', stateMin)  learnLessState  state'  Q)"
  proof-
    {
      fix Q :: "State set" and state :: State
      assume "state  Q"
      let ?M = "(getM state)"
      let ?C = "(getC state)"
      let ?conflictFlag = "(getConflictFlag state)"
      let ?Q1 = "{F::Formula.  state. state  Q  
        (getM state) = ?M   (getConflictFlag state) = ?conflictFlag  (getC state) = ?C  (getF state) = F}"
      from state  Q 
      have "getF state  ?Q1"
        by auto      
      with wfLearnLess[of "?C"]
      obtain Fmin where "Fmin  ?Q1" "F'. (F', Fmin)  learnLess ?C  F'  ?Q1"
        unfolding wf_eq_minimal
        apply (erule_tac x="?Q1" in allE)
        apply (erule_tac x="getF state" in allE)
        by auto
      from Fmin  ?Q1 obtain stateMin
        where "stateMin  Q" "(getM stateMin) = ?M" "getC stateMin = ?C" "getConflictFlag stateMin = ?conflictFlag" "getF stateMin = Fmin"
        by auto
      have "state'. (state', stateMin)  learnLessState  state'  Q"
      proof
        fix state'
        show "(state', stateMin)  learnLessState  state'  Q"
        proof
          assume "(state', stateMin)  learnLessState"
          with ‹getM stateMin = ?M ‹getC stateMin = ?C ‹getConflictFlag stateMin = ?conflictFlag
          have "getM state' = getM stateMin" "getC state' = getC stateMin" 
            "getConflictFlag state' = getConflictFlag stateMin" "(getF state', getF stateMin)  learnLess ?C"
            unfolding learnLessState_def
            by auto
          from F'. (F', Fmin)  learnLess ?C  F'  ?Q1
            (getF state', getF stateMin)  learnLess ?C ‹getF stateMin = Fmin
          have "getF state'  ?Q1"
            by simp
          with ‹getM state' = getM stateMin ‹getC state' = getC stateMin ‹getConflictFlag state' = getConflictFlag stateMin
            ‹getM stateMin = ?M ‹getC stateMin = ?C ‹getConflictFlag stateMin = ?conflictFlag ‹getF stateMin = Fmin
          show "state'  Q"
            by auto
        qed
      qed
      with stateMin  Q 
      have " stateMin  Q. (state'. (state', stateMin)  learnLessState  state'  Q)"
        by auto
    }
    thus ?thesis
      by auto
  qed
qed

text‹Now we can prove the following key lemma which shows that the
termination ordering is well founded.›
lemma wfTerminationLess:
  fixes decisionVars::"Variable set" and F0::"Formula"
  assumes "finite decisionVars"
  shows "wf (terminationLess F0 decisionVars)"
  unfolding wf_eq_minimal
proof-
  show "Q state. state  Q  ( stateMin  Q. state'. (state', stateMin)  terminationLess F0 decisionVars  state'  Q)"
  proof-
    {
      fix Q::"State set"
      fix state::State
      assume "state  Q"

      from ‹finite decisionVars
      have "wf (lexLessState F0 decisionVars)"
        using wfLexLessState[of "decisionVars" "F0"]
        by simp

      with state  Q obtain state0
        where "state0  Q" "state'. (state', state0)  lexLessState F0 decisionVars  state'  Q"
        unfolding wf_eq_minimal
        by auto
      let ?Q0 = "{state. state  Q  (getM state) = (getM state0)}"
      from state0  Q
      have "state0  ?Q0"
        by simp
      have "wf boolLessState"
        using wfBoolLessState
        .
      with state0  Q obtain state1
        where "state1  ?Q0" "state'. (state', state1)  boolLessState  state'  ?Q0"
        unfolding wf_eq_minimal
        apply (erule_tac x="?Q0" in allE)
        apply (erule_tac x="state0" in allE)
        by auto
      let ?Q1 = "{state. state  Q  getM state = getM state0  getConflictFlag state = getConflictFlag state1}"
      from state1  ?Q0
      have "state1  ?Q1"
        by simp
      have "wf multLessState"
        using wfMultLessState
        .
      with state1  ?Q1 obtain state2
        where "state2  ?Q1" "state'. (state', state2)  multLessState  state'  ?Q1"
        unfolding wf_eq_minimal
        apply (erule_tac x="?Q1" in allE)
        apply (erule_tac x="state1" in allE)
        by auto
      let ?Q2 = "{state. state  Q  getM state = getM state0  
        getConflictFlag state = getConflictFlag state1   getC state = getC state2}"
      from state2  ?Q1
      have "state2  ?Q2"
        by simp
      have "wf learnLessState"
        using wfLearnLessState
        .
      with state2  ?Q2 obtain state3
        where "state3  ?Q2" "state'. (state', state3)  learnLessState  state'  ?Q2"
        unfolding wf_eq_minimal
        apply (erule_tac x="?Q2" in allE)
        apply (erule_tac x="state2" in allE)
        by auto
      from state3  ?Q2
      have "state3  Q"
        by simp
      from state1  ?Q0
      have "getM state1 = getM state0"
        by simp
      from state2  ?Q1
      have "getM state2 = getM state0" "getConflictFlag state2 = getConflictFlag state1"
        by auto
      from state3  ?Q2
      have "getM state3 = getM state0" "getConflictFlag state3 = getConflictFlag state1" "getC state3 = getC state2"
        by auto
      let ?stateMin = state3
      have "state'. (state', ?stateMin)  terminationLess F0 decisionVars  state'  Q"
      proof
        fix state'
        show "(state', ?stateMin)  terminationLess F0 decisionVars  state'  Q"
        proof
          assume "(state', ?stateMin)  terminationLess F0 decisionVars"
          hence 
            "(state', ?stateMin)  lexLessState F0 decisionVars 
            (state', ?stateMin)  boolLessState 
            (state', ?stateMin)  multLessState 
            (state', ?stateMin)  learnLessState"
            unfolding terminationLess_def
            by auto
          moreover
          {
            assume "(state', ?stateMin)  lexLessState F0 decisionVars"
            with ‹getM state3 = getM state0
            have "(state', state0)  lexLessState F0 decisionVars"
              unfolding lexLessState_def
              by simp
            with state'. (state', state0)  lexLessState F0 decisionVars  state'  Q
            have "state'  Q"
              by simp
          }
          moreover
          {
            assume "(state', ?stateMin)  boolLessState"
            from ?stateMin  ?Q2
              ‹getM state1 = getM state0
            have "getConflictFlag state3 = getConflictFlag state1" "getM state3 = getM state1"
              by auto
            with (state', ?stateMin)  boolLessState›
            have "(state', state1)  boolLessState"
              unfolding boolLessState_def
              by simp
            with state'. (state', state1)  boolLessState  state'  ?Q0
            have "state'  ?Q0"
              by simp
            from (state', state1)  boolLessState› ‹getM state1 = getM state0
            have "getM state' = getM state0"
              unfolding boolLessState_def
              by auto
            with state'  ?Q0
            have "state'  Q"
              by simp
          }
          moreover
          {
            assume "(state', ?stateMin)  multLessState"
            from ?stateMin  ?Q2 
              ‹getM state1 = getM state0 ‹getM state2 = getM state0
              ‹getConflictFlag state2 = getConflictFlag state1
            have "getC state3 = getC state2" "getConflictFlag state3 = getConflictFlag state2" "getM state3 = getM state2"
              by auto
            with (state', ?stateMin)  multLessState›
            have "(state', state2)  multLessState"
              unfolding multLessState_def
              by auto
            with state'. (state', state2)  multLessState  state'  ?Q1
            have "state'  ?Q1"
              by simp
            from (state', state2)  multLessState› ‹getM state2 = getM state0 ‹getConflictFlag state2 = getConflictFlag state1
            have "getM state' = getM state0" "getConflictFlag state' = getConflictFlag state1"
              unfolding multLessState_def
              by auto
            with state'  ?Q1
            have "state'  Q"
              by simp
          }
          moreover
          {
            assume "(state', ?stateMin)  learnLessState"
            with state'. (state', ?stateMin)  learnLessState  state'  ?Q2
            have "state'  ?Q2"
              by simp
            from (state', ?stateMin)  learnLessState›
              ‹getM state3 = getM state0 ‹getConflictFlag state3 = getConflictFlag state1 ‹getC state3 = getC state2
            have "getM state' = getM state0" "getConflictFlag state' = getConflictFlag state1" "getC state' = getC state2"
              unfolding learnLessState_def
              by auto
            with state'  ?Q2
            have "state'  Q"
              by simp
          }
          ultimately
          show "state'  Q"
            by auto
        qed
      qed
      with ?stateMin  Q have "( stateMin  Q. state'. (state', stateMin)  terminationLess F0 decisionVars  state'  Q)"
        by auto
    }
    thus ?thesis
      by simp
  qed
qed


text‹Using the termination ordering we show that the transition
 relation is well founded on states reachable from initial state.›
(*----------------------------------------------------------------------------*)
theorem wfTransitionRelation:
  fixes decisionVars :: "Variable set" and F0 :: "Formula"
  assumes "finite decisionVars" and "isInitialState state0 F0"
  shows "wf {(stateB, stateA). 
             (state0, stateA)  transitionRelation F0 decisionVars  (transition stateA stateB F0 decisionVars)}"
(*----------------------------------------------------------------------------*)
proof-
  let ?rel = "{(stateB, stateA). 
                  (state0, stateA)  transitionRelation F0 decisionVars  (transition stateA stateB F0 decisionVars)}"
  let ?rel'= "terminationLess F0 decisionVars"

  have "x y. (x, y)  ?rel  (x, y)  ?rel'"
  proof-
    {
      fix stateA::State and stateB::State
      assume "(stateB, stateA)  ?rel"
      hence "(stateB, stateA)  ?rel'"
        using ‹isInitialState state0 F0
        using invariantsHoldInValidRunsFromInitialState[of "state0" "F0" "stateA" "decisionVars"]
        using stateIsDecreasedByValidTransitions[of "stateA" "F0" "decisionVars" "stateB"]
        by simp
    }
    thus ?thesis
      by simp
  qed
  moreover 
  have "wf ?rel'"
    using ‹finite decisionVars
    by (rule wfTerminationLess)
  ultimately
  show ?thesis
    using wellFoundedEmbed[of "?rel" "?rel'"]
    by simp
qed


text‹We will now give two corollaries of the previous theorem. First
  is a weak termination result that shows that there is a terminating
  run from every intial state to the final one.›
corollary 
  fixes decisionVars :: "Variable set" and F0 :: "Formula" and state0 :: "State"
  assumes "finite decisionVars" and "isInitialState state0 F0"
  shows " state. (state0, state)  transitionRelation F0 decisionVars  isFinalState state F0 decisionVars"
proof-
  {
    assume "¬ ?thesis"
    let ?Q = "{state. (state0, state)  transitionRelation F0 decisionVars}"
    let ?rel = "{(stateB, stateA). (state0, stateA)  transitionRelation F0 decisionVars 
                         transition stateA stateB F0 decisionVars}"
    have "state0  ?Q"
      unfolding transitionRelation_def
      by simp
    hence " state. state  ?Q"
      by auto

    from assms 
    have "wf ?rel"
      using wfTransitionRelation[of "decisionVars" "state0" "F0"]
      by auto
    hence " Q. ( x. x  Q)  ( stateMin  Q.  state. (state, stateMin)  ?rel  state  Q)"
      unfolding wf_eq_minimal
      by simp
    hence " ( x. x  ?Q)  ( stateMin  ?Q.  state. (state, stateMin)  ?rel  state  ?Q)"
      by rule
    with  state. state  ?Q
    have " stateMin  ?Q.  state. (state, stateMin)  ?rel  state  ?Q"
      by simp
    then obtain stateMin
      where "stateMin  ?Q" and " state. (state, stateMin)  ?rel  state  ?Q"
      by auto
    
    from stateMin  ?Q 
    have "(state0, stateMin)  transitionRelation F0 decisionVars"
      by simp
    with ¬ ?thesis
    have "¬ isFinalState stateMin F0 decisionVars"
      by simp
    then obtain state'::State
      where "transition stateMin state' F0 decisionVars"
      unfolding isFinalState_def
      by auto
    have "(state', stateMin)  ?rel"
      using (state0, stateMin)  transitionRelation F0 decisionVars
            ‹transition stateMin state' F0 decisionVars
      by simp
    with  state. (state, stateMin)  ?rel  state  ?Q
    have "state'  ?Q"
      by force
    moreover
    from (state0, stateMin)  transitionRelation F0 decisionVars ‹transition stateMin state' F0 decisionVars
    have "state'  ?Q"
      unfolding transitionRelation_def
      using rtrancl_into_rtrancl[of "state0" "stateMin" "{(stateA, stateB). transition stateA stateB F0 decisionVars}" "state'"]
      by simp
    ultimately
    have False
      by simp
  }
  thus ?thesis
    by auto
qed

text‹Now we prove the final strong termination result which states
that there cannot be infinite chains of transitions. If there is an
infinite transition chain that starts from an initial state, its
elements would for a set that would contain initial state and for
every element of that set there would be another element of that set
that is directly reachable from it. We show that no such set exists.›
corollary noInfiniteTransitionChains:
  fixes F0::Formula and decisionVars::"Variable set"
  assumes "finite decisionVars"
  shows "¬ ( Q::(State set).  state0  Q. isInitialState state0 F0  
                              ( state  Q. ( state'  Q. transition state state' F0 decisionVars))
            )"
proof-
  {
  assume "¬ ?thesis"
  then obtain Q::"State set" and state0::"State"
    where "isInitialState state0 F0" "state0  Q"
          " state  Q. ( state'  Q. transition state state' F0 decisionVars)"
    by auto
  let ?rel = "{(stateB, stateA). (state0, stateA)  transitionRelation F0 decisionVars 
                         transition stateA stateB F0 decisionVars}"
  from ‹finite decisionVars ‹isInitialState state0 F0
  have "wf ?rel"
    using wfTransitionRelation
    by simp
  hence wfmin: "Q x. x  Q 
         (zQ. y. (y, z)  ?rel  y  Q)"
    unfolding wf_eq_minimal 
    by simp
  let ?Q = "{state  Q. (state0, state)  transitionRelation F0 decisionVars}"
  from state0  Q
  have "state0  ?Q"
    unfolding transitionRelation_def
    by simp
  with wfmin
  obtain stateMin::State
    where "stateMin  ?Q" and "y. (y, stateMin)  ?rel  y  ?Q"
    apply (erule_tac x="?Q" in allE)
    by auto

  from stateMin  ?Q
  have "stateMin  Q" "(state0, stateMin)  transitionRelation F0 decisionVars"
    by auto
  with  state  Q. ( state'  Q. transition state state' F0 decisionVars)
  obtain state'::State
    where "state'  Q" "transition stateMin state' F0 decisionVars"
    by auto

  with (state0, stateMin)  transitionRelation F0 decisionVars
  have "(state', stateMin)  ?rel"
    by simp
  with y. (y, stateMin)  ?rel  y  ?Q
  have "state'  ?Q"
    by force
  
  from state'  Q (state0, stateMin)  transitionRelation F0 decisionVars
    ‹transition stateMin state' F0 decisionVars
  have "state'  ?Q"
    unfolding transitionRelation_def
    using rtrancl_into_rtrancl[of "state0" "stateMin" "{(stateA, stateB). transition stateA stateB F0 decisionVars}" "state'"]
    by simp
  with state'  ?Q
  have False
    by simp
  }
  thus ?thesis
    by force
qed


(*----------------------------------------------------------------------------*)
subsection‹Completeness›
(*----------------------------------------------------------------------------*)
text‹In this section we will first show that each final state is
either \textit{SAT} or \textit{UNSAT} state.›


lemma finalNonConflictState: 
  fixes state::State and FO :: Formula
  assumes 
  "getConflictFlag state = False" and
  "¬ applicableDecide state decisionVars"  and
  "¬ applicableConflict state"
  shows "¬ formulaFalse (getF state) (elements (getM state))" and 
  "vars (elements (getM state))  decisionVars"
proof-
  from ¬ applicableConflict state ‹getConflictFlag state = False›
  show "¬ formulaFalse (getF state) (elements (getM state))"
    unfolding applicableConflictCharacterization
    by (auto simp add:formulaFalseIffContainsFalseClause formulaEntailsItsClauses)
  show "vars (elements (getM state))  decisionVars"
  proof
    fix x :: Variable
    let ?l = "Pos x"
    assume "x  decisionVars"
    hence "var ?l = x" and "var ?l  decisionVars" and "var (opposite ?l)  decisionVars"
      by auto
    with ¬ applicableDecide state decisionVars 
    have "literalTrue ?l (elements (getM state))  literalFalse ?l (elements (getM state))"
      unfolding applicableDecideCharacterization
      by force
    with ‹var ?l = x
    show "x  vars (elements (getM state))"
      using valuationContainsItsLiteralsVariable[of "?l" "elements (getM state)"]
      using valuationContainsItsLiteralsVariable[of "opposite ?l" "elements (getM state)"]
      by auto
  qed
qed

lemma finalConflictingState: 
  fixes state :: State
  assumes 
  "InvariantUniq (getM state)" and
  "InvariantReasonClauses (getF state) (getM state)" and
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)" and
  "¬ applicableExplain state" and
  "¬ applicableBackjump state" and
  "getConflictFlag state"
  shows
  "getC state = []"
proof (cases " l. l el getC state  opposite l el decisions (getM state)")
  case True
  {
    assume "getC state  []"
    let ?l = "getLastAssertedLiteral (oppositeLiteralList (getC state)) (elements (getM state))"

    from ‹InvariantUniq (getM state)
    have "uniq (elements (getM state))"
      unfolding InvariantUniq_def
      .
   
    from ‹getConflictFlag state ‹InvariantCFalse (getConflictFlag state) (getM state) (getC state)
    have "clauseFalse (getC state) (elements (getM state))"
      unfolding InvariantCFalse_def
      by simp

    with ‹getC state  []
    ‹InvariantUniq (getM state)
    have "isLastAssertedLiteral ?l (oppositeLiteralList (getC state)) (elements (getM state))"
      unfolding InvariantUniq_def
      using getLastAssertedLiteralCharacterization
      by simp

    with True ‹uniq (elements (getM state))
    have " level. (isBackjumpLevel level (opposite ?l) (getC state) (getM state))"
      using allDecisionsThenExistsBackjumpLevel [of "getM state" "getC state" "opposite ?l"]
      by simp
    then
    obtain level::nat where
      "isBackjumpLevel level (opposite ?l) (getC state) (getM state)"
      by auto
    with ‹getConflictFlag state
    have "applicableBackjump state"
      unfolding applicableBackjumpCharacterization
      by auto
    with ¬ applicableBackjump state
    have False
      by simp
  }
  thus ?thesis
    by auto
next
  case False
  then obtain literal::Literal where "literal el getC state" "¬ opposite literal el decisions (getM state)"
    by auto
  with ‹InvariantReasonClauses (getF state) (getM state) ‹InvariantCFalse (getConflictFlag state) (getM state) (getC state) ‹getConflictFlag state
  have " c. formulaEntailsClause (getF state) c  isReason c (opposite literal) (elements (getM state))"
    using explainApplicableToEachNonDecision[of "getF state" "getM state" "getConflictFlag state" "getC state" "opposite literal"]
    by auto
  then obtain c::Clause 
    where "formulaEntailsClause (getF state) c" "isReason c (opposite literal) (elements (getM state))"
    by auto
  with ¬ applicableExplain state ‹getConflictFlag state literal el (getC state)
  have "False"
    unfolding applicableExplainCharacterization
    by auto
  thus ?thesis
    by simp
qed
  
lemma finalStateCharacterizationLemma:
  fixes state :: State
  assumes 
  "InvariantUniq (getM state)" and
  "InvariantReasonClauses (getF state) (getM state)" and
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)" and
  "¬ applicableDecide state decisionVars"  and
  "¬ applicableConflict state"
  "¬ applicableExplain state" and
  "¬ applicableBackjump state"
  shows
  "(getConflictFlag state = False  
           ¬formulaFalse (getF state) (elements (getM state))  
           vars (elements (getM state))  decisionVars)  
   (getConflictFlag state = True  
           getC state = [])"
proof (cases "getConflictFlag state")
  case True
  hence "getC state = []"
    using assms
    using finalConflictingState
    by auto
  with True 
  show ?thesis
    by simp
next
  case False
  hence "¬formulaFalse (getF state) (elements (getM state))" and "vars (elements (getM state))  decisionVars"
    using assms
    using finalNonConflictState
    by auto
  with False
  show ?thesis
    by simp
qed

(*----------------------------------------------------------------------------*)
theorem finalStateCharacterization:
  fixes F0 :: Formula and decisionVars :: "Variable set" and state0 :: State and state :: State
  assumes 
  "isInitialState state0 F0" and
  "(state0, state)  transitionRelation F0 decisionVars" and
  "isFinalState state F0 decisionVars"
  shows 
  "(getConflictFlag state = False  
      ¬formulaFalse (getF state) (elements (getM state))  
      vars (elements (getM state))  decisionVars)  
   (getConflictFlag state = True  
      getC state = [])"
(*----------------------------------------------------------------------------*)
proof-
  from ‹isInitialState state0 F0 (state0, state)  transitionRelation F0 decisionVars
  have "invariantsHoldInState state F0 decisionVars"
    using invariantsHoldInValidRunsFromInitialState
    by simp
  hence 
    *: "InvariantUniq (getM state)" 
    "InvariantReasonClauses (getF state) (getM state)" 
    "InvariantCFalse (getConflictFlag state) (getM state) (getC state)"
    unfolding invariantsHoldInState_def
    by auto

  from ‹isFinalState state F0 decisionVars 
  have **: 
    "¬ applicableDecide state decisionVars"
    "¬ applicableConflict state"
    "¬ applicableExplain  state" 
    "¬ applicableLearn state" 
    "¬ applicableBackjump state" 
    unfolding finalStateNonApplicable
    by auto

  from * **
  show ?thesis
    using finalStateCharacterizationLemma[of "state" "decisionVars"]
    by simp
qed

text‹Completeness theorems are easy consequences of this characterization and 
 soundness.›
(*----------------------------------------------------------------------------*)
theorem completenessForSAT: 
  fixes F0 :: Formula and decisionVars :: "Variable set" and state0 :: State and state :: State
  assumes 
  "satisfiable F0" and 

  "isInitialState state0 F0" and
  "(state0, state)  transitionRelation F0 decisionVars" and
  "isFinalState state F0 decisionVars"

  shows "getConflictFlag state = False  ¬formulaFalse (getF state) (elements (getM state))  
               vars (elements (getM state))  decisionVars"
(*----------------------------------------------------------------------------*)
proof-
  from assms
  have *: "(getConflictFlag state = False  
               ¬formulaFalse (getF state) (elements (getM state))  
               vars (elements (getM state))  decisionVars)  
           (getConflictFlag state = True  
               getC state = [])"
    using finalStateCharacterization[of "state0" "F0" "state" "decisionVars"]
    by auto
  {
    assume "¬ (getConflictFlag state = False)"
    with * 
    have "getConflictFlag state = True" "getC state = []"
      by auto
    with assms
      have "¬ satisfiable F0"
      using soundnessForUNSAT
      by simp
    with ‹satisfiable F0
    have False
      by simp
  }
  with * show ?thesis
    by auto
qed

(************************************************************************)
theorem completenessForUNSAT: 
  fixes F0 :: Formula and decisionVars :: "Variable set" and state0 :: State and state :: State
  assumes 
  "vars F0  decisionVars" and

  "¬ satisfiable F0" and

  "isInitialState state0 F0" and
  "(state0, state)  transitionRelation F0 decisionVars" and
  "isFinalState state F0 decisionVars"

  shows 
  "getConflictFlag state = True  getC state = []"
(************************************************************************)
proof-
  from assms
  have *: "(getConflictFlag state = False  
               ¬formulaFalse (getF state) (elements (getM state))  
               vars (elements (getM state))  decisionVars)  
           (getConflictFlag state = True  
               getC state = [])"
    using finalStateCharacterization[of "state0" "F0" "state" "decisionVars"]
    by auto
  {
    assume "¬ getConflictFlag state = True"
    with *
    have "getConflictFlag state = False  ¬formulaFalse (getF state) (elements (getM state))  vars (elements (getM state))  decisionVars"
      by simp
    with assms
    have "satisfiable F0"
      using soundnessForSAT[of "F0" "decisionVars" "state0" "state"]
      unfolding satisfiable_def
      by auto
    with ¬ satisfiable F0
    have False
      by simp
  }
  with * show ?thesis
    by auto
qed

(************************************************************************)
theorem partialCorrectness: 
  fixes F0 :: Formula and decisionVars :: "Variable set" and state0 :: State and state :: State
  assumes 
  "vars F0  decisionVars" and  

  "isInitialState state0 F0" and
  "(state0, state)  transitionRelation F0 decisionVars" and
  "isFinalState state F0 decisionVars"

  shows 
  "satisfiable F0 = (¬ getConflictFlag state)"
(************************************************************************)
using assms
using completenessForUNSAT[of "F0" "decisionVars" "state0" "state"]
using completenessForSAT[of "F0" "state0" "state" "decisionVars"]
by auto

end

Theory SatSolverCode

(*    Title:              SatSolverVerification/SatSolverCode.thy
      Author:             Filip Maric
      Maintainer:         Filip Maric <filip at matf.bg.ac.yu>
*)

section‹Functional implementation of a SAT solver with Two Watch literal propagation.›
theory SatSolverCode
imports SatSolverVerification "HOL-Library.Code_Target_Numeral"
begin

(******************************************************************************)
subsection‹Specification›
(******************************************************************************)

lemma [code_unfold]:
  fixes literal :: Literal and clause :: Clause
  shows "literal el clause = List.member clause literal"
  by (auto simp add: member_def)

datatype ExtendedBool = TRUE | FALSE | UNDEF

record State = 
  ― ‹Satisfiability flag: UNDEF, TRUE or FALSE›
"getSATFlag" :: ExtendedBool
  ― ‹Formula› 
"getF"       :: Formula      
  ― ‹Assertion Trail›
"getM"       :: LiteralTrail 
  ― ‹Conflict flag›
"getConflictFlag"   :: bool   ― ‹raised iff M falsifies F›
  ― ‹Conflict clause index› 
"getConflictClause" :: nat    ― ‹corresponding clause from F is false in M›
  ― ‹Unit propagation queue›
"getQ" :: "Literal list"      
  ― ‹Unit propagation graph›
"getReason" :: "Literal  nat option" ― ‹index of a clause that is a reason for propagation of a literal›
  ― ‹Two-watch literal scheme›
  ― ‹clause indices instead of clauses are used›
"getWatch1" :: "nat  Literal option"  ― ‹First watch of a clause›
"getWatch2" :: "nat  Literal option"  ― ‹Second watch of a clause›
"getWatchList" :: "Literal  nat list" ― ‹Watch list of a given literal›
  ― ‹Conflict analysis data structures›
"getC"   :: Clause             ― ‹Conflict analysis clause - always false in M›
"getCl"  :: Literal            ― ‹Last asserted literal in (opposite getC)›
"getCll" :: Literal            ― ‹Second last asserted literal in (opposite getC)›
"getCn"  :: nat                ― ‹Number of literals of (opposite getC) on the (currentLevel M)›

definition
setWatch1 :: "nat  Literal  State  State"
where
"setWatch1 clause literal state =
    state getWatch1 := (getWatch1 state)(clause := Some literal), 
           getWatchList := (getWatchList state)(literal := clause # (getWatchList state literal)) 
         
"
declare setWatch1_def[code_unfold]

definition
setWatch2 :: "nat  Literal  State  State"
where
"setWatch2 clause literal state =
    state getWatch2 := (getWatch2 state)(clause := Some literal),
           getWatchList := (getWatchList state)(literal := clause # (getWatchList state literal)) 
         
"
declare setWatch2_def[code_unfold]


definition
swapWatches :: "nat  State  State"
where
"swapWatches clause state ==
    state getWatch1 := (getWatch1 state)(clause := (getWatch2 state clause)),
           getWatch2 := (getWatch2 state)(clause := (getWatch1 state clause))
         
"
declare swapWatches_def[code_unfold]

primrec getNonWatchedUnfalsifiedLiteral :: "Clause  Literal  Literal  LiteralTrail  Literal option"
where
"getNonWatchedUnfalsifiedLiteral [] w1 w2 M = None" |
"getNonWatchedUnfalsifiedLiteral (literal # clause) w1 w2 M = 
    (if literal  w1  
        literal  w2  
        ¬ (literalFalse literal (elements M)) then
            Some literal
     else
            getNonWatchedUnfalsifiedLiteral clause w1 w2 M
    )
"

definition
setReason :: "Literal  nat  State  State"
where
"setReason literal clause state = 
    state getReason := (getReason state)(literal := Some clause) 
"
declare setReason_def[code_unfold]

primrec notifyWatches_loop::"Literal  nat list  nat list  State  State"
where
"notifyWatches_loop literal [] newWl state = state getWatchList := (getWatchList state)(literal := newWl) " |
"notifyWatches_loop literal (clause # list') newWl state = 
    (let state' = (if Some literal = (getWatch1 state clause) then 
                       (swapWatches clause state) 
                   else 
                       state) in
    case (getWatch1 state' clause) of 
        None  state
    |   Some w1  (
    case (getWatch2 state' clause) of 
        None  state
    |   Some w2  
    (if (literalTrue w1 (elements (getM state'))) then
        notifyWatches_loop literal list' (clause # newWl) state'
     else
        (case (getNonWatchedUnfalsifiedLiteral (nth (getF state') clause) w1 w2 (getM state')) of 
            Some l'  
                notifyWatches_loop literal list' newWl (setWatch2 clause l' state')
          | None  
                (if (literalFalse w1 (elements (getM state'))) then
                    let state'' = (state' getConflictFlag := True, getConflictClause := clause ) in
                    notifyWatches_loop literal list' (clause # newWl) state''
                else
                    let state'' = state' getQ := (if w1 el (getQ state') then 
                                                      (getQ state') 
                                                  else 
                                                      (getQ state') @ [w1] 
                                                  )
                                         in
                   let state''' = (setReason w1 clause state'') in
                   notifyWatches_loop literal list' (clause # newWl) state'''
                )
        )
    )
    )
    )
"

definition
notifyWatches :: "Literal  State  State"
where
"notifyWatches literal state ==
    notifyWatches_loop literal (getWatchList state literal) [] state
"
declare notifyWatches_def[code_unfold]


definition
assertLiteral :: "Literal  bool  State  State"
where
"assertLiteral literal decision state ==
    let state' = (state getM := (getM state) @ [(literal, decision)] ) in
    notifyWatches (opposite literal) state'
"


definition
applyUnitPropagate :: "State  State"
where
"applyUnitPropagate state =
    (let state' = (assertLiteral (hd (getQ state)) False state) in
    state' getQ := tl (getQ state'))
"

partial_function (tailrec)
exhaustiveUnitPropagate :: "State  State"
where
exhaustiveUnitPropagate_unfold[code]:
"exhaustiveUnitPropagate state =
    (if (getConflictFlag state)  (getQ state) = [] then 
        state 
    else 
        exhaustiveUnitPropagate (applyUnitPropagate state)
    )
"

inductive
exhaustiveUnitPropagate_dom :: "State  bool"
where
step: "(¬ getConflictFlag state  getQ state  []
    exhaustiveUnitPropagate_dom (applyUnitPropagate state))
    exhaustiveUnitPropagate_dom state"


definition
addClause :: "Clause  State  State"
where
"addClause clause state =
    (let clause' = (remdups (removeFalseLiterals clause (elements (getM state)))) in 
    (if (clauseTrue clause' (elements (getM state))) then 
        state
    else (if clause'=[] then 
        state getSATFlag := FALSE 
    else (if (length clause' = 1) then 
        let state' = (assertLiteral (hd clause') False state) in
        exhaustiveUnitPropagate state'
    else (if (clauseTautology clause') then 
        state
    else
        let clauseIndex = length (getF state) in
        let state'   = state getF := (getF state) @ [clause'] in
        let state''  = setWatch1 clauseIndex (nth clause' 0) state' in
        let state''' = setWatch2 clauseIndex (nth clause' 1) state'' in
        state'''
   )))
 ))"


definition
initialState :: "State"
where
"initialState =
     getSATFlag = UNDEF,
      getF = [], 
      getM = [], 
      getConflictFlag = False,
      getConflictClause = 0, 
      getQ = [],
      getReason = λ l. None,
      getWatch1 = λ c. None, 
      getWatch2 = λ c. None,
      getWatchList = λ l. [],
      getC = [],
      getCl = (Pos 0), 
      getCll = (Pos 0), 
      getCn = 0
    
"

primrec initialize :: "Formula  State  State"
where
"initialize [] state = state" |
"initialize (clause # formula) state = initialize formula (addClause clause state)"

definition 
findLastAssertedLiteral :: "State  State"
where
"findLastAssertedLiteral state = 
   state  getCl := getLastAssertedLiteral (oppositeLiteralList (getC state)) (elements (getM state)) "

definition
countCurrentLevelLiterals :: "State  State"
where
"countCurrentLevelLiterals state = 
   (let cl = currentLevel (getM state) in 
        state  getCn := length (filter (λ l. elementLevel (opposite l) (getM state) = cl) (getC state)) )"

definition setConflictAnalysisClause :: "Clause  State  State" 
where 
"setConflictAnalysisClause clause state = 
  (let oppM0 = oppositeLiteralList (elements (prefixToLevel 0 (getM state))) in 
   let state' = state (| getC := remdups (list_diff clause oppM0) |) in 
     countCurrentLevelLiterals (findLastAssertedLiteral state')
  )"
 
definition
applyConflict :: "State  State"
where
"applyConflict state = 
   (let conflictClause = (nth (getF state) (getConflictClause state)) in
    setConflictAnalysisClause conflictClause state)"

definition
applyExplain :: "Literal  State  State"
where
"applyExplain literal state =
    (case (getReason state literal) of
        None  
            state
    |   Some reason  
            let res = resolve (getC state) (nth (getF state) reason) (opposite literal) in 
            setConflictAnalysisClause res state
        
    )
"

partial_function (tailrec)
applyExplainUIP :: "State  State"
where
applyExplainUIP_unfold:
"applyExplainUIP state = 
    (if (getCn state = 1) then 
         state
     else
         applyExplainUIP (applyExplain (getCl state) state)
    )
"

inductive
applyExplainUIP_dom :: "State  bool"
where
step:
"(getCn state  1
     applyExplainUIP_dom (applyExplain (getCl state) state))
   applyExplainUIP_dom state
"

definition
applyLearn :: "State  State"
where
"applyLearn state =
        (if getC state = [opposite (getCl state)] then
            state
         else
            let state' = state getF := (getF state) @ [getC state]  in
            let l  = (getCl state) in
            let ll = (getLastAssertedLiteral (removeAll l (oppositeLiteralList (getC state))) (elements (getM state))) in
            let clauseIndex = length (getF state) in
            let state''  = setWatch1 clauseIndex (opposite l) state' in
            let state''' = setWatch2 clauseIndex (opposite ll) state'' in
            state''' getCll := ll 
        )
"

definition
getBackjumpLevel :: "State  nat"
where
"getBackjumpLevel state ==
    (if getC state = [opposite (getCl state)] then 
        0 
     else
        elementLevel (getCll state) (getM state)
     )
"

definition
applyBackjump :: "State  State"
where
"applyBackjump state =
    (let l = (getCl state) in
     let level = getBackjumpLevel state in
     let state' = state getConflictFlag := False, getQ := [], getM := (prefixToLevel level (getM state)) in
     let state'' = (if level > 0 then setReason (opposite l) (length (getF state) - 1) state' else state') in
     assertLiteral (opposite l) False state''
    )
"

axiomatization selectLiteral :: "State  Variable set  Literal"
where
selectLiteral_def:
"Vbl - vars (elements (getM state))  {}  
    var (selectLiteral state Vbl)  (Vbl - vars (elements (getM state)))"

definition
applyDecide :: "State  Variable set  State"
where
"applyDecide state Vbl =
    assertLiteral (selectLiteral state Vbl) True state
"

definition
solve_loop_body :: "State  Variable set  State"
where
"solve_loop_body state Vbl = 
    (let state' = exhaustiveUnitPropagate state in
    (if (getConflictFlag state') then
        (if (currentLevel (getM state')) = 0 then
            state' getSATFlag := FALSE 
         else
            (applyBackjump
            (applyLearn
            (applyExplainUIP 
            (applyConflict
                state'
            )
            )
            )
            )
         )
     else
        (if (vars (elements (getM state'))  Vbl) then
            state' getSATFlag := TRUE 
         else
            applyDecide state' Vbl
        )
    )
    )
"


partial_function (tailrec) 
solve_loop :: "State  Variable set  State"
where
solve_loop_unfold: 
"solve_loop state Vbl = 
    (if (getSATFlag state)  UNDEF then
        state
     else 
        let state' = solve_loop_body state Vbl in
        solve_loop state' Vbl
    )
"

inductive
solve_loop_dom :: "State  Variable set  bool"
where
step:
"(getSATFlag state = UNDEF
     solve_loop_dom (solve_loop_body state Vbl) Vbl)
   solve_loop_dom state Vbl"

definition solve::"Formula  ExtendedBool"
where
"solve F0 = 
    (getSATFlag 
        (solve_loop 
            (initialize F0 initialState) (vars F0)
        )
    )
"

(* 
code_modulename SML
  Nat Numbers
  Int Numbers
  Ring_and_Field Numbers

code_modulename OCaml
  Nat Numbers
  Int Numbers
  Ring_and_Field Numbers

export_code solve in OCaml file "code/solve.ML"
                  in SML file "code/solve.ocaml
                  in Haskell file "code/"
*)

(******************************************************************************)
(*      I N V A R I A N T S                                                   *)
(******************************************************************************)

definition
InvariantWatchListsContainOnlyClausesFromF :: "(Literal  nat list)  Formula  bool"
where
"InvariantWatchListsContainOnlyClausesFromF Wl F = 
    ( (l::Literal) (c::nat). c   set (Wl l)  0  c  c < length F)
"

definition
InvariantWatchListsUniq :: "(Literal  nat list)  bool"
where
"InvariantWatchListsUniq Wl =
    ( l. uniq (Wl l))
"

definition
InvariantWatchListsCharacterization :: "(Literal  nat list)  (nat  Literal option)  (nat  Literal option)  bool"
where
"InvariantWatchListsCharacterization Wl w1 w2 = 
    ( (c::nat) (l::Literal). c  set (Wl l) = (Some l = (w1 c)  Some l = (w2 c)))
"

definition
InvariantWatchesEl :: "Formula  (nat  Literal option)  (nat  Literal option)  bool"
where
"InvariantWatchesEl formula watch1 watch2 == 
     (clause::nat). 0  clause  clause < length formula  
        ( (w1::Literal) (w2::Literal). watch1 clause = Some w1  watch2 clause = Some w2  
             w1 el (nth formula clause)  w2 el (nth formula clause))
"

definition
InvariantWatchesDiffer :: "Formula  (nat  Literal option)  (nat  Literal option)  bool"
where
"InvariantWatchesDiffer formula watch1 watch2 == 
     (clause::nat). 0  clause  clause < length formula  watch1 clause  watch2 clause
"

definition
watchCharacterizationCondition::"Literal  Literal  LiteralTrail  Clause  bool"
where
"watchCharacterizationCondition w1 w2 M clause = 
    (literalFalse w1 (elements M)  
        ( ( l. l el clause  literalTrue l (elements M)  elementLevel l M  elementLevel (opposite w1) M) 
          ( l. l el clause  l  w1  l  w2  
                literalFalse l (elements M)  elementLevel (opposite l) M  elementLevel (opposite w1) M)
          )
    )
"

definition
InvariantWatchCharacterization::"Formula  (nat  Literal option)  (nat  Literal option)  LiteralTrail  bool"
where
"InvariantWatchCharacterization F watch1 watch2 M =
    ( c w1 w2. (0  c  c < length F  Some w1 = watch1 c  Some w2 = watch2 c)  
          watchCharacterizationCondition w1 w2 M (nth F c)  
          watchCharacterizationCondition w2 w1 M (nth F c)
    )
"

definition
InvariantQCharacterization :: "bool  Literal list  Formula  LiteralTrail  bool"
where
"InvariantQCharacterization conflictFlag Q F M ==
   ¬ conflictFlag  ( (l::Literal). l el Q = ( (c::Clause). c el F  isUnitClause c l (elements M)))
"

definition
InvariantUniqQ :: "Literal list  bool"
where
"InvariantUniqQ Q = 
    uniq Q
"

definition
InvariantConflictFlagCharacterization :: "bool  Formula  LiteralTrail  bool"
where
"InvariantConflictFlagCharacterization conflictFlag F M ==
    conflictFlag = formulaFalse F (elements M)
"

definition
InvariantNoDecisionsWhenConflict :: "Formula  LiteralTrail  nat  bool"
where
"InvariantNoDecisionsWhenConflict F M level= 
    ( level'. level' < level  
              ¬ formulaFalse F (elements (prefixToLevel level' M))
    )
"

definition
InvariantNoDecisionsWhenUnit :: "Formula  LiteralTrail  nat  bool"
where
"InvariantNoDecisionsWhenUnit F M level = 
    ( level'. level' < level  
              ¬ ( clause literal. clause el F 
                                   isUnitClause clause literal (elements (prefixToLevel level' M)))
    )
"

definition InvariantEquivalentZL :: "Formula  LiteralTrail  Formula  bool"
where
"InvariantEquivalentZL F M F0 = 
    equivalentFormulae (F @ val2form (elements (prefixToLevel 0 M))) F0
"

definition
InvariantGetReasonIsReason :: "(Literal  nat option)  Formula  LiteralTrail  Literal set  bool"
where
"InvariantGetReasonIsReason GetReason F M Q == 
      literal. (literal el (elements M)  ¬ literal el (decisions M)  elementLevel literal M > 0  
                   ( (reason::nat). (GetReason literal) = Some reason  0  reason  reason < length F  
                         isReason (nth F reason) literal (elements M)
                   )
                 )  
                (currentLevel M > 0  literal  Q  
                   ( (reason::nat). (GetReason literal) = Some reason  0  reason  reason < length F  
                         (isUnitClause (nth F reason) literal (elements M)  clauseFalse (nth F reason) (elements M))
                   )
                 )
"

definition
InvariantConflictClauseCharacterization :: "bool  nat  Formula  LiteralTrail  bool"
where
"InvariantConflictClauseCharacterization conflictFlag conflictClause F M  ==
         conflictFlag  (conflictClause < length F  
                           clauseFalse (nth F conflictClause) (elements M))"

definition
InvariantClCharacterization :: "Literal  Clause  LiteralTrail  bool" 
where
"InvariantClCharacterization Cl C M == 
  isLastAssertedLiteral Cl (oppositeLiteralList C) (elements M)"

definition
InvariantCllCharacterization :: "Literal  Literal  Clause  LiteralTrail  bool" 
where
"InvariantCllCharacterization Cl Cll C M == 
  set C  {opposite Cl}  
      isLastAssertedLiteral Cll (removeAll Cl (oppositeLiteralList C)) (elements M)"

definition
InvariantClCurrentLevel :: "Literal  LiteralTrail  bool"
where
"InvariantClCurrentLevel Cl M == 
  elementLevel Cl M = currentLevel M"

definition
InvariantCnCharacterization :: "nat  Clause  LiteralTrail  bool"
where
"InvariantCnCharacterization Cn C M == 
  Cn = length (filter (λ l. elementLevel (opposite l) M = currentLevel M) (remdups C))
"

definition
InvariantUniqC :: "Clause  bool"
where
"InvariantUniqC clause = uniq clause"

definition
InvariantVarsQ :: "Literal list  Formula  Variable set  bool"
where
"InvariantVarsQ Q F0 Vbl ==
  vars Q  vars F0  Vbl"

(******************************************************************************)

end

Theory AssertLiteral

(*    Title:              SatSolverVerification/AssertLiteral.thy
      Author:             Filip Maric
      Maintainer:         Filip Maric <filip at matf.bg.ac.yu>
*)

theory AssertLiteral
imports SatSolverCode
begin

(*****************************************************************************)
(*   G E T   N O N   W A T C H E D  U N F A L S I F I E D   L I T E R A L    *)
(*****************************************************************************)

lemma getNonWatchedUnfalsifiedLiteralSomeCharacterization:
fixes clause :: Clause and w1 :: Literal and w2 :: Literal and M :: LiteralTrail and l :: Literal
assumes 
  "getNonWatchedUnfalsifiedLiteral clause w1 w2 M = Some l"
shows 
  "l el clause" "l  w1" "l  w2" "¬ literalFalse l (elements M)"
using assms
by (induct clause) (auto split: if_split_asm)

lemma getNonWatchedUnfalsifiedLiteralNoneCharacterization:
fixes clause :: Clause and w1 :: Literal and w2 :: Literal and M :: LiteralTrail
assumes 
  "getNonWatchedUnfalsifiedLiteral clause w1 w2 M = None"
shows 
  " l. l el clause  l  w1  l  w2  literalFalse l (elements M)"
using assms
by (induct clause) (auto split: if_split_asm)

(*****************************************************************************)
(*   S W A P   W A T C H E S                                                 *)
(*****************************************************************************)

lemma swapWatchesEffect:
fixes clause::nat and state::State and clause'::nat
shows
  "getWatch1 (swapWatches clause state) clause' = (if clause = clause' then getWatch2 state clause' else getWatch1 state clause')" and
  "getWatch2 (swapWatches clause state) clause' = (if clause = clause' then getWatch1 state clause' else getWatch2 state clause')"
unfolding swapWatches_def
by auto

(*****************************************************************************)
(*    N O T I F Y    W A T C H E S                                           *)
(*****************************************************************************)

lemma notifyWatchesLoopPreservedVariables:
fixes literal :: Literal and Wl :: "nat list" and newWl :: "nat list" and state :: State 
assumes 
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  " (c::nat). c  set Wl  0  c  c < length (getF state)"
shows
  "let state' = (notifyWatches_loop literal Wl newWl state) in
   (getM state') = (getM state)  
   (getF state') = (getF state)  
   (getSATFlag state') = (getSATFlag state)  
   isPrefix (getQ state) (getQ state')
  " 
using assms
proof (induct Wl arbitrary: newWl state)
  case Nil
  thus ?case
    unfolding isPrefix_def
    by simp
next
  case (Cons clause Wl')
  from  (c::nat). c  set (clause # Wl')  0  c  c < length (getF state)
  have "0  clause  clause < length (getF state)"
    by auto
  then obtain wa::Literal and wb::Literal
    where "getWatch1 state clause = Some wa" and "getWatch2 state clause = Some wb"
    using Cons
    unfolding InvariantWatchesEl_def
    by auto
  show ?case
  proof (cases "Some literal = getWatch1 state clause")
    case True
    let ?state' = "swapWatches clause state"
    let ?w1 = wb
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch2 state clause = Some wb
      unfolding swapWatches_def
      by auto
    let ?w2 = wa
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch1 state clause = Some wa
      unfolding swapWatches_def
      by auto    
    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True
      
      from Cons(2)
      have "InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
        unfolding InvariantWatchesEl_def
        unfolding swapWatches_def
        by auto
      moreover
      have "getM ?state' = getM state  
        getF ?state' = getF state  
        getSATFlag ?state' = getSATFlag state  
        getQ ?state' = getQ state
        "
        unfolding swapWatches_def
        by simp
      ultimately
      show ?thesis
        using Cons(1)[of "?state'" "clause # newWl"]
        using Cons(3)
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹Some literal = getWatch1 state clause
        using ‹literalTrue ?w1 (elements (getM ?state'))
        by (simp add:Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state') clause)"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by simp

        let ?state'' = "setWatch2 clause l' ?state'"

        from Cons(2)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state') clause)
          unfolding InvariantWatchesEl_def
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        moreover
        have "getM ?state'' = getM state 
          getF ?state'' = getF state  
          getSATFlag ?state'' = getSATFlag state  
          getQ ?state'' = getQ state"
          unfolding swapWatches_def
          unfolding setWatch2_def
          by simp
        ultimately
        show ?thesis
          using Cons(1)[of "?state''" "newWl"]
          using Cons(3)
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ‹Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using Some
          by (simp add: Let_def)
      next
        case None
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            by auto
          moreover
          have "getM ?state'' = getM state 
          getF ?state'' = getF state  
          getSATFlag ?state'' = getSATFlag state  
            getQ ?state'' = getQ state"
            unfolding swapWatches_def
            by simp
          ultimately
          show ?thesis
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(3)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            by (simp add: Let_def)
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"
          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          have "getM ?state'' = getM state 
            getF ?state'' = getF state  
            getSATFlag ?state'' = getSATFlag state  
            getQ ?state'' = (if ?w1 el (getQ state) then (getQ state) else (getQ state) @ [?w1])"
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          ultimately
          show ?thesis
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(3)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            unfolding isPrefix_def
            by (auto simp add: Let_def split: if_split_asm)
        qed
      qed
    qed
  next
    case False
    let ?state' = state
    let ?w1 = wa
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch1 state clause = Some wa
      unfolding swapWatches_def
      by auto
    let ?w2 = wb
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch2 state clause = Some wb
      unfolding swapWatches_def
      by auto    
    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True
      thus ?thesis
        using Cons
        using ¬ Some literal = getWatch1 state clause
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹literalTrue ?w1 (elements (getM ?state'))
        by (simp add:Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state')) clause"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by simp

        let ?state'' = "setWatch2 clause l' ?state'"

        from Cons(2)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state')) clause
          unfolding InvariantWatchesEl_def
          unfolding setWatch2_def
          by auto
        moreover
        have "getM ?state'' = getM state 
          getF ?state'' = getF state  
          getSATFlag ?state'' = getSATFlag state  
          getQ ?state'' = getQ state"
          unfolding setWatch2_def
          by simp
        ultimately
        show ?thesis
          using Cons(1)[of "?state''"]
          using Cons(3)
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ¬ Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using Some
          by (simp add: Let_def)
      next
        case None
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            by auto
          moreover
          have "getM ?state'' = getM state 
            getF ?state'' = getF state  
            getSATFlag ?state'' = getSATFlag state  
            getQ ?state'' = getQ state"
            by simp
          ultimately
          show ?thesis
            using Cons(1)[of "?state''"]
            using Cons(3)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ¬ Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            by (simp add: Let_def)
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"
          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding setReason_def
            by auto
          moreover
          have "getM ?state'' = getM state 
            getF ?state'' = getF state  
            getSATFlag ?state'' = getSATFlag state 
            getQ ?state'' = (if ?w1 el (getQ state) then (getQ state) else (getQ state) @ [?w1])"
            unfolding setReason_def
            by simp
          ultimately
          show ?thesis
            using Cons(1)[of "?state''"]
            using Cons(3)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ¬ Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            unfolding isPrefix_def
            by (auto simp add: Let_def split: if_split_asm)
        qed
      qed
    qed
  qed
qed


lemma notifyWatchesStartQIreleveant:
fixes literal :: Literal and Wl :: "nat list" and newWl :: "nat list" and state :: State 
assumes 
  "InvariantWatchesEl (getF stateA) (getWatch1 stateA) (getWatch2 stateA)" and 
  " (c::nat). c  set Wl  0  c  c < length (getF stateA)" and
  "getM stateA = getM stateB" and
  "getF stateA = getF stateB" and
  "getWatch1 stateA = getWatch1 stateB" and
  "getWatch2 stateA = getWatch2 stateB" and
  "getConflictFlag stateA = getConflictFlag stateB" and
  "getSATFlag stateA = getSATFlag stateB"
shows
  "let state' = (notifyWatches_loop literal Wl newWl stateA) in
   let state'' = (notifyWatches_loop literal Wl newWl stateB) in
     (getM state') = (getM state'')  
     (getF state') = (getF state'')  
     (getSATFlag state') = (getSATFlag state'')  
     (getConflictFlag state') = (getConflictFlag state'')
  " 
using assms
proof (induct Wl arbitrary: newWl stateA stateB)
  case Nil
  thus ?case
    by simp
next
  case (Cons clause Wl')
  from  (c::nat). c  set (clause # Wl')  0  c  c < length (getF stateA)
  have "0  clause  clause < length (getF stateA)"
    by auto
  then obtain wa::Literal and wb::Literal
    where "getWatch1 stateA clause = Some wa" and "getWatch2 stateA clause = Some wb"
    using Cons
    unfolding InvariantWatchesEl_def
    by auto
  show ?case
  proof (cases "Some literal = getWatch1 stateA clause")
    case True
    hence "Some literal = getWatch1 stateB clause"
      using ‹getWatch1 stateA = getWatch1 stateB
      by simp

    let ?state'A = "swapWatches clause stateA"
    let ?state'B = "swapWatches clause stateB"

    have 
      "getM ?state'A = getM ?state'B"
      "getF ?state'A = getF ?state'B"
      "getWatch1 ?state'A = getWatch1 ?state'B"
      "getWatch2 ?state'A = getWatch2 ?state'B"
      "getConflictFlag ?state'A = getConflictFlag ?state'B"
      "getSATFlag ?state'A = getSATFlag ?state'B"
      using Cons
      unfolding swapWatches_def
      by auto

    let ?w1 = wb
    have "getWatch1 ?state'A clause = Some ?w1"
      using ‹getWatch2 stateA clause = Some wb
      unfolding swapWatches_def
      by auto
    hence "getWatch1 ?state'B clause = Some ?w1"
      using ‹getWatch1 ?state'A = getWatch1 ?state'B
      by simp
    let ?w2 = wa
    have "getWatch2 ?state'A clause = Some ?w2"
      using ‹getWatch1 stateA clause = Some wa
      unfolding swapWatches_def
      by auto    
    hence "getWatch2 ?state'B clause = Some ?w2"
      using ‹getWatch2 ?state'A = getWatch2 ?state'B
      by simp

    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'A))")
      case True
      hence "literalTrue ?w1 (elements (getM ?state'B))"
        using ‹getM ?state'A = getM ?state'B
        by simp
      
      from Cons(2)
      have "InvariantWatchesEl (getF ?state'A) (getWatch1 ?state'A) (getWatch2 ?state'A)"
        unfolding InvariantWatchesEl_def
        unfolding swapWatches_def
        by auto
      moreover
      have "getM ?state'A = getM stateA  
        getF ?state'A = getF stateA  
        getSATFlag ?state'A = getSATFlag stateA  
        getQ ?state'A = getQ stateA
        "
        unfolding swapWatches_def
        by simp
      moreover
      have "getM ?state'B = getM stateB  
        getF ?state'B = getF stateB  
        getSATFlag ?state'B = getSATFlag stateB  
        getQ ?state'B = getQ stateB
        "
        unfolding swapWatches_def
        by simp
      ultimately
      show ?thesis
        using Cons(1)[of "?state'A" "?state'B" "clause # newWl"]
        using ‹getM ?state'A = getM ?state'B
        using ‹getF ?state'A = getF ?state'B
        using ‹getWatch1 ?state'A = getWatch1 ?state'B
        using ‹getWatch2 ?state'A = getWatch2 ?state'B
        using ‹getConflictFlag ?state'A = getConflictFlag ?state'B
        using ‹getSATFlag ?state'A = getSATFlag ?state'B
        using Cons(3)
        using ‹getWatch1 ?state'A clause = Some ?w1
        using ‹getWatch2 ?state'A clause = Some ?w2
        using ‹getWatch1 ?state'B clause = Some ?w1
        using ‹getWatch2 ?state'B clause = Some ?w2
        using ‹Some literal = getWatch1 stateA clause
        using ‹Some literal = getWatch1 stateB clause
        using ‹literalTrue ?w1 (elements (getM ?state'A))
        using ‹literalTrue ?w1 (elements (getM ?state'B))
        by (simp add:Let_def)
    next
      case False
      hence "¬ literalTrue ?w1 (elements (getM ?state'B))"
        using ‹getM ?state'A = getM ?state'B
        by simp
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state'A) clause) ?w1 ?w2 (getM ?state'A)")
        case (Some l')
        hence "getNonWatchedUnfalsifiedLiteral (nth (getF ?state'B) clause) ?w1 ?w2 (getM ?state'B) = Some l'"
          using ‹getF ?state'A = getF ?state'B
          using ‹getM ?state'A = getM ?state'B
          by simp

        have "l' el (nth (getF ?state'A) clause)"
          using Some
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by simp
        hence "l' el (nth (getF ?state'B) clause)"
          using ‹getF ?state'A = getF ?state'B
          by simp


        let ?state''A = "setWatch2 clause l' ?state'A"
        let ?state''B = "setWatch2 clause l' ?state'B"

        have 
          "getM ?state''A = getM ?state''B"
          "getF ?state''A = getF ?state''B"
          "getWatch1 ?state''A = getWatch1 ?state''B"
          "getWatch2 ?state''A = getWatch2 ?state''B"
          "getConflictFlag ?state''A = getConflictFlag ?state''B"
          "getSATFlag ?state''A = getSATFlag ?state''B"
          using Cons
          unfolding setWatch2_def
          unfolding swapWatches_def
          by auto


        from Cons(2)
        have "InvariantWatchesEl (getF ?state''A) (getWatch1 ?state''A) (getWatch2 ?state''A)"
          using l' el (nth (getF ?state'A) clause)
          unfolding InvariantWatchesEl_def
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        moreover
        have "getM ?state''A = getM stateA 
          getF ?state''A = getF stateA  
          getSATFlag ?state''A = getSATFlag stateA  
          getQ ?state''A = getQ stateA"
          unfolding swapWatches_def
          unfolding setWatch2_def
          by simp
        moreover
        have "getM ?state''B = getM stateB  
          getF ?state''B = getF stateB  
          getSATFlag ?state''B = getSATFlag stateB  
          getQ ?state''B = getQ stateB
          "
          unfolding swapWatches_def
          unfolding setWatch2_def
          by simp
        ultimately
        show ?thesis
          using Cons(1)[of "?state''A" "?state''B" "newWl"]
          using ‹getM ?state''A = getM ?state''B
          using ‹getF ?state''A = getF ?state''B
          using ‹getWatch1 ?state''A = getWatch1 ?state''B
          using ‹getWatch2 ?state''A = getWatch2 ?state''B
          using ‹getConflictFlag ?state''A = getConflictFlag ?state''B
          using ‹getSATFlag ?state''A = getSATFlag ?state''B
          using Cons(3)
          using ‹getWatch1 ?state'A clause = Some ?w1
          using ‹getWatch2 ?state'A clause = Some ?w2
          using ‹getWatch1 ?state'B clause = Some ?w1
          using ‹getWatch2 ?state'B clause = Some ?w2
          using ‹Some literal = getWatch1 stateA clause
          using ‹Some literal = getWatch1 stateB clause
          using ¬ literalTrue ?w1 (elements (getM ?state'A))
          using ¬ literalTrue ?w1 (elements (getM ?state'B))
          using ‹getNonWatchedUnfalsifiedLiteral (nth (getF ?state'A) clause) ?w1 ?w2 (getM ?state'A) = Some l'
          using ‹getNonWatchedUnfalsifiedLiteral (nth (getF ?state'B) clause) ?w1 ?w2 (getM ?state'B) = Some l'
          by (simp add:Let_def)
      next
        case None
        hence "getNonWatchedUnfalsifiedLiteral (nth (getF ?state'B) clause) ?w1 ?w2 (getM ?state'B) = None"
          using ‹getF ?state'A = getF ?state'B ‹getM ?state'A = getM ?state'B
          by simp
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'A))")
          case True
          hence "literalFalse ?w1 (elements (getM ?state'B))"
            using ‹getM ?state'A = getM ?state'B
            by simp

          let ?state''A = "?state'AgetConflictFlag := True, getConflictClause := clause"
          let ?state''B = "?state'BgetConflictFlag := True, getConflictClause := clause"
          have 
            "getM ?state''A = getM ?state''B"
            "getF ?state''A = getF ?state''B"
            "getWatch1 ?state''A = getWatch1 ?state''B"
            "getWatch2 ?state''A = getWatch2 ?state''B"
            "getConflictFlag ?state''A = getConflictFlag ?state''B"
            "getSATFlag ?state''A = getSATFlag ?state''B"
            using Cons
            unfolding swapWatches_def
            by auto
          
          from Cons(2)
          have "InvariantWatchesEl (getF ?state''A) (getWatch1 ?state''A) (getWatch2 ?state''A)"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            by auto
          moreover
          have "getM ?state''A = getM stateA 
          getF ?state''A = getF stateA  
          getSATFlag ?state''A = getSATFlag stateA  
            getQ ?state''A = getQ stateA"
            unfolding swapWatches_def
            by simp
          moreover
          have "getM ?state''B = getM stateB 
          getF ?state''B = getF stateB  
          getSATFlag ?state''B = getSATFlag stateB  
            getQ ?state''B = getQ stateB"
            unfolding swapWatches_def
            by simp
          ultimately
          show ?thesis
            using Cons(4) Cons(5)
            using Cons(1)[of "?state''A" "?state''B" "clause # newWl"]
            using ‹getM ?state''A = getM ?state''B
            using ‹getF ?state''A = getF ?state''B
            using ‹getWatch1 ?state''A = getWatch1 ?state''B
            using ‹getWatch2 ?state''A = getWatch2 ?state''B
            using ‹getConflictFlag ?state''A = getConflictFlag ?state''B
            using ‹getSATFlag ?state''A = getSATFlag ?state''B
            using Cons(3)
            using ‹getWatch1 ?state'A clause = Some ?w1
            using ‹getWatch2 ?state'A clause = Some ?w2
            using ‹getWatch1 ?state'B clause = Some ?w1
            using ‹getWatch2 ?state'B clause = Some ?w2
            using ‹Some literal = getWatch1 stateA clause
            using ‹Some literal = getWatch1 stateB clause
            using ¬ literalTrue ?w1 (elements (getM ?state'A))
            using ¬ literalTrue ?w1 (elements (getM ?state'B))
            using ‹getNonWatchedUnfalsifiedLiteral (nth (getF ?state'A) clause) ?w1 ?w2 (getM ?state'A) = None›
            using ‹getNonWatchedUnfalsifiedLiteral (nth (getF ?state'B) clause) ?w1 ?w2 (getM ?state'B) = None›
            using ‹literalFalse ?w1 (elements (getM ?state'A))
            using ‹literalFalse ?w1 (elements (getM ?state'B))
            by (simp add:Let_def)
        next
          case False
          hence "¬ literalFalse ?w1 (elements (getM ?state'B))"
            using ‹getM ?state'A = getM ?state'B
            by simp
          let ?state''A = "setReason ?w1 clause (?state'AgetQ := (if ?w1 el (getQ ?state'A) then (getQ ?state'A) else (getQ ?state'A) @ [?w1]))"
          let ?state''B = "setReason ?w1 clause (?state'BgetQ := (if ?w1 el (getQ ?state'B) then (getQ ?state'B) else (getQ ?state'B) @ [?w1]))"
          
          have 
            "getM ?state''A = getM ?state''B"
            "getF ?state''A = getF ?state''B"
            "getWatch1 ?state''A = getWatch1 ?state''B"
            "getWatch2 ?state''A = getWatch2 ?state''B"
            "getConflictFlag ?state''A = getConflictFlag ?state''B"
            "getSATFlag ?state''A = getSATFlag ?state''B"
            using Cons
            unfolding setReason_def
            unfolding swapWatches_def
            by auto

          from Cons(2)
          have "InvariantWatchesEl (getF ?state''A) (getWatch1 ?state''A) (getWatch2 ?state''A)"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          have "getM ?state''A = getM stateA 
            getF ?state''A = getF stateA  
            getSATFlag ?state''A = getSATFlag stateA  
            getQ ?state''A = (if ?w1 el (getQ stateA) then (getQ stateA) else (getQ stateA) @ [?w1])"
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          have "getM ?state''B = getM stateB 
            getF ?state''B = getF stateB  
            getSATFlag ?state''B = getSATFlag stateB  
            getQ ?state''B = (if ?w1 el (getQ stateB) then (getQ stateB) else (getQ stateB) @ [?w1])"
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          ultimately
          show ?thesis
            using Cons(4) Cons(5)
            using Cons(1)[of "?state''A" "?state''B" "clause # newWl"]
            using ‹getM ?state''A = getM ?state''B
            using ‹getF ?state''A = getF ?state''B
            using ‹getWatch1 ?state''A = getWatch1 ?state''B
            using ‹getWatch2 ?state''A = getWatch2 ?state''B
            using ‹getConflictFlag ?state''A = getConflictFlag ?state''B
            using ‹getSATFlag ?state''A = getSATFlag ?state''B
            using Cons(3)
            using ‹getWatch1 ?state'A clause = Some ?w1
            using ‹getWatch2 ?state'A clause = Some ?w2
            using ‹getWatch1 ?state'B clause = Some ?w1
            using ‹getWatch2 ?state'B clause = Some ?w2
            using ‹Some literal = getWatch1 stateA clause
            using ‹Some literal = getWatch1 stateB clause
            using ¬ literalTrue ?w1 (elements (getM ?state'A))
            using ¬ literalTrue ?w1 (elements (getM ?state'B))
            using ‹getNonWatchedUnfalsifiedLiteral (nth (getF ?state'A) clause) ?w1 ?w2 (getM ?state'A) = None›
            using ‹getNonWatchedUnfalsifiedLiteral (nth (getF ?state'B) clause) ?w1 ?w2 (getM ?state'B) = None›
            using ¬ literalFalse ?w1 (elements (getM ?state'A))
            using ¬ literalFalse ?w1 (elements (getM ?state'B))
            by (simp add:Let_def)
        qed
      qed
    qed
  next
    case False
    hence "Some literal  getWatch1 stateB clause"
      using Cons
      by simp

    let ?state'A = stateA
    let ?state'B = stateB

    have 
      "getM ?state'A = getM ?state'B"
      "getF ?state'A = getF ?state'B"
      "getWatch1 ?state'A = getWatch1 ?state'B"
      "getWatch2 ?state'A = getWatch2 ?state'B"
      "getConflictFlag ?state'A = getConflictFlag ?state'B"
      "getSATFlag ?state'A = getSATFlag ?state'B"
      using Cons
      by auto

    let ?w1 = wa
    have "getWatch1 ?state'A clause = Some ?w1"
      using ‹getWatch1 stateA clause = Some wa
      by auto
    hence "getWatch1 ?state'B clause = Some ?w1"
      using Cons
      by simp
    let ?w2 = wb
    have "getWatch2 ?state'A clause = Some ?w2"
      using ‹getWatch2 stateA clause = Some wb
      by auto
    hence "getWatch2 ?state'B clause = Some ?w2"
      using Cons
      by simp

    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'A))")
      case True
      hence "literalTrue ?w1 (elements (getM ?state'B))"
        using Cons
        by simp

      show ?thesis
        using Cons(1)[of "?state'A" "?state'B" "clause # newWl"]
        using Cons(2) Cons(3) Cons(4) Cons(5) Cons(6) Cons(7) Cons(8) Cons(9)
        using ¬ Some literal = getWatch1 stateA clause
        using ¬ Some literal = getWatch1 stateB clause
        using ‹getWatch1 ?state'A clause = Some ?w1
        using ‹getWatch1 ?state'B clause = Some ?w1
        using ‹getWatch2 ?state'A clause = Some ?w2
        using ‹getWatch2 ?state'B clause = Some ?w2
        using ‹literalTrue ?w1 (elements (getM ?state'A))
        using ‹literalTrue ?w1 (elements (getM ?state'B))
        by (simp add:Let_def)
    next
      case False
      hence "¬ literalTrue ?w1 (elements (getM ?state'B))"
        using ‹getM ?state'A = getM ?state'B
        by simp
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state'A) clause) ?w1 ?w2 (getM ?state'A)")
        case (Some l')
        hence "getNonWatchedUnfalsifiedLiteral (nth (getF ?state'B) clause) ?w1 ?w2 (getM ?state'B) = Some l'"
          using ‹getF ?state'A = getF ?state'B
          using ‹getM ?state'A = getM ?state'B
          by simp

        have "l' el (nth (getF ?state'A) clause)"
          using Some
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by simp
        hence "l' el (nth (getF ?state'B) clause)"
          using ‹getF ?state'A = getF ?state'B
          by simp

        let ?state''A = "setWatch2 clause l' ?state'A"
        let ?state''B = "setWatch2 clause l' ?state'B"

        have 
          "getM ?state''A = getM ?state''B"
          "getF ?state''A = getF ?state''B"
          "getWatch1 ?state''A = getWatch1 ?state''B"
          "getWatch2 ?state''A = getWatch2 ?state''B"
          "getConflictFlag ?state''A = getConflictFlag ?state''B"
          "getSATFlag ?state''A = getSATFlag ?state''B"
          using Cons
          unfolding setWatch2_def
          by auto


        from Cons(2)
        have "InvariantWatchesEl (getF ?state''A) (getWatch1 ?state''A) (getWatch2 ?state''A)"
          using l' el (nth (getF ?state'A) clause)
          unfolding InvariantWatchesEl_def
          unfolding setWatch2_def
          by auto
        moreover
        have "getM ?state''A = getM stateA 
          getF ?state''A = getF stateA  
          getSATFlag ?state''A = getSATFlag stateA  
          getQ ?state''A = getQ stateA"
          unfolding setWatch2_def
          by simp
        ultimately
        show ?thesis
          using Cons(1)[of "?state''A" "?state''B" "newWl"]
          using ‹getM ?state''A = getM ?state''B
          using ‹getF ?state''A = getF ?state''B
          using ‹getWatch1 ?state''A = getWatch1 ?state''B
          using ‹getWatch2 ?state''A = getWatch2 ?state''B
          using ‹getConflictFlag ?state''A = getConflictFlag ?state''B
          using ‹getSATFlag ?state''A = getSATFlag ?state''B
          using Cons(3)
          using ‹getWatch1 ?state'A clause = Some ?w1
          using ‹getWatch2 ?state'A clause = Some ?w2
          using ‹getWatch1 ?state'B clause = Some ?w1
          using ‹getWatch2 ?state'B clause = Some ?w2
          using ¬ Some literal = getWatch1 stateA clause
          using ¬ Some literal = getWatch1 stateB clause
          using ¬ literalTrue ?w1 (elements (getM ?state'A))
          using ¬ literalTrue ?w1 (elements (getM ?state'B))
          using ‹getNonWatchedUnfalsifiedLiteral (nth (getF ?state'A) clause) ?w1 ?w2 (getM ?state'A) = Some l'
          using ‹getNonWatchedUnfalsifiedLiteral (nth (getF ?state'B) clause) ?w1 ?w2 (getM ?state'B) = Some l'
          by (simp add:Let_def)
      next
        case None
        hence "getNonWatchedUnfalsifiedLiteral (nth (getF ?state'B) clause) ?w1 ?w2 (getM ?state'B) = None"
          using ‹getF ?state'A = getF ?state'B ‹getM ?state'A = getM ?state'B
          by simp
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'A))")
          case True
          hence "literalFalse ?w1 (elements (getM ?state'B))"
            using ‹getM ?state'A = getM ?state'B
            by simp

          let ?state''A = "?state'AgetConflictFlag := True, getConflictClause := clause"
          let ?state''B = "?state'BgetConflictFlag := True, getConflictClause := clause"
          have 
            "getM ?state''A = getM ?state''B"
            "getF ?state''A = getF ?state''B"
            "getWatch1 ?state''A = getWatch1 ?state''B"
            "getWatch2 ?state''A = getWatch2 ?state''B"
            "getConflictFlag ?state''A = getConflictFlag ?state''B"
            "getSATFlag ?state''A = getSATFlag ?state''B"
            using Cons
            by auto
          
          from Cons(2)
          have "InvariantWatchesEl (getF ?state''A) (getWatch1 ?state''A) (getWatch2 ?state''A)"
            unfolding InvariantWatchesEl_def
            by auto
          moreover
          have "getM ?state''A = getM stateA 
          getF ?state''A = getF stateA  
          getSATFlag ?state''A = getSATFlag stateA  
            getQ ?state''A = getQ stateA"
            by simp
          ultimately
          show ?thesis
            using Cons(4) Cons(5)
            using Cons(1)[of "?state''A" "?state''B" "clause # newWl"]
            using ‹getM ?state''A = getM ?state''B
            using ‹getF ?state''A = getF ?state''B
            using ‹getWatch1 ?state''A = getWatch1 ?state''B
            using ‹getWatch2 ?state''A = getWatch2 ?state''B
            using ‹getConflictFlag ?state''A = getConflictFlag ?state''B
            using ‹getSATFlag ?state''A = getSATFlag ?state''B
            using Cons(3)
            using ‹getWatch1 ?state'A clause = Some ?w1
            using ‹getWatch2 ?state'A clause = Some ?w2
            using ‹getWatch1 ?state'B clause = Some ?w1
            using ‹getWatch2 ?state'B clause = Some ?w2
            using ¬ Some literal = getWatch1 stateA clause
            using ¬ Some literal = getWatch1 stateB clause
            using ¬ literalTrue ?w1 (elements (getM ?state'A))
            using ¬ literalTrue ?w1 (elements (getM ?state'B))
            using ‹getNonWatchedUnfalsifiedLiteral (nth (getF ?state'A) clause) ?w1 ?w2 (getM ?state'A) = None›
            using ‹getNonWatchedUnfalsifiedLiteral (nth (getF ?state'B) clause) ?w1 ?w2 (getM ?state'B) = None›
            using ‹literalFalse ?w1 (elements (getM ?state'A))
            using ‹literalFalse ?w1 (elements (getM ?state'B))
            by (simp add:Let_def)
        next
          case False
          hence "¬ literalFalse ?w1 (elements (getM ?state'B))"
            using ‹getM ?state'A = getM ?state'B
            by simp
          let ?state''A = "setReason ?w1 clause (?state'AgetQ := (if ?w1 el (getQ ?state'A) then (getQ ?state'A) else (getQ ?state'A) @ [?w1]))"
          let ?state''B = "setReason ?w1 clause (?state'BgetQ := (if ?w1 el (getQ ?state'B) then (getQ ?state'B) else (getQ ?state'B) @ [?w1]))"
          
          have 
            "getM ?state''A = getM ?state''B"
            "getF ?state''A = getF ?state''B"
            "getWatch1 ?state''A = getWatch1 ?state''B"
            "getWatch2 ?state''A = getWatch2 ?state''B"
            "getConflictFlag ?state''A = getConflictFlag ?state''B"
            "getSATFlag ?state''A = getSATFlag ?state''B"
            using Cons
            unfolding setReason_def
            by auto

          from Cons(2)
          have "InvariantWatchesEl (getF ?state''A) (getWatch1 ?state''A) (getWatch2 ?state''A)"
            unfolding InvariantWatchesEl_def
            unfolding setReason_def
            by auto
          moreover
          have "getM ?state''A = getM stateA 
            getF ?state''A = getF stateA  
            getSATFlag ?state''A = getSATFlag stateA  
            getQ ?state''A = (if ?w1 el (getQ stateA) then (getQ stateA) else (getQ stateA) @ [?w1])"
            unfolding setReason_def
            by auto
          ultimately
          show ?thesis
            using Cons(4) Cons(5)
            using Cons(1)[of "?state''A" "?state''B" "clause # newWl"]
            using ‹getM ?state''A = getM ?state''B
            using ‹getF ?state''A = getF ?state''B
            using ‹getWatch1 ?state''A = getWatch1 ?state''B
            using ‹getWatch2 ?state''A = getWatch2 ?state''B
            using ‹getConflictFlag ?state''A = getConflictFlag ?state''B
            using ‹getSATFlag ?state''A = getSATFlag ?state''B
            using Cons(3)
            using ‹getWatch1 ?state'A clause = Some ?w1
            using ‹getWatch2 ?state'A clause = Some ?w2
            using ‹getWatch1 ?state'B clause = Some ?w1
            using ‹getWatch2 ?state'B clause = Some ?w2
            using ¬ Some literal = getWatch1 stateA clause
            using ¬ Some literal = getWatch1 stateB clause
            using ¬ literalTrue ?w1 (elements (getM ?state'A))
            using ¬ literalTrue ?w1 (elements (getM ?state'B))
            using ‹getNonWatchedUnfalsifiedLiteral (nth (getF ?state'A) clause) ?w1 ?w2 (getM ?state'A) = None›
            using ‹getNonWatchedUnfalsifiedLiteral (nth (getF ?state'B) clause) ?w1 ?w2 (getM ?state'B) = None›
            using ¬ literalFalse ?w1 (elements (getM ?state'A))
            using ¬ literalFalse ?w1 (elements (getM ?state'B))
            by (simp add:Let_def)
        qed
      qed
    qed
  qed
qed

lemma notifyWatchesLoopPreservedWatches:
fixes literal :: Literal and Wl :: "nat list" and newWl :: "nat list" and state :: State 
assumes 
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  " (c::nat). c  set Wl  0  c  c < length (getF state)"
shows
  "let state' = (notifyWatches_loop literal Wl newWl state) in
      c. c  set Wl  (getWatch1 state' c) = (getWatch1 state c)  (getWatch2 state' c) = (getWatch2 state c)
  " 
using assms
proof (induct Wl arbitrary: newWl state)
  case Nil
  thus ?case
    by simp
next
  case (Cons clause Wl')
  from  (c::nat). c  set (clause # Wl')  0  c  c < length (getF state)
  have "0  clause  clause < length (getF state)"
    by auto
  then obtain wa::Literal and wb::Literal
    where "getWatch1 state clause = Some wa" and "getWatch2 state clause = Some wb"
    using Cons
    unfolding InvariantWatchesEl_def
    by auto
  show ?case
  proof (cases "Some literal = getWatch1 state clause")
    case True
    let ?state' = "swapWatches clause state"
    let ?w1 = wb
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch2 state clause = Some wb
      unfolding swapWatches_def
      by auto
    let ?w2 = wa
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch1 state clause = Some wa
      unfolding swapWatches_def
      by auto    
    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True
      
      from Cons(2)
      have "InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
        unfolding InvariantWatchesEl_def
        unfolding swapWatches_def
        by auto
      moreover
      have "getM ?state' = getM state  
        getF ?state' = getF state"
        unfolding swapWatches_def
        by simp
      ultimately
      show ?thesis
        using Cons(1)[of "?state'" "clause # newWl"]
        using Cons(3)
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹Some literal = getWatch1 state clause
        using ‹literalTrue ?w1 (elements (getM ?state'))
        apply (simp add:Let_def)
        unfolding swapWatches_def
        by simp
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state') clause)"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by simp

        let ?state'' = "setWatch2 clause l' ?state'"

        from Cons(2)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state') clause)
          unfolding InvariantWatchesEl_def
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        moreover
        have "getM ?state'' = getM state 
          getF ?state'' = getF state"
          unfolding swapWatches_def
          unfolding setWatch2_def
          by simp
        ultimately
        show ?thesis
          using Cons(1)[of "?state''" "newWl"]
          using Cons(3)
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ‹Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using Some
          apply (simp add: Let_def)
          unfolding setWatch2_def
          unfolding swapWatches_def
          by simp
      next
        case None
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            by auto
          moreover
          have "getM ?state'' = getM state 
          getF ?state'' = getF state"
            unfolding swapWatches_def
            by simp
          ultimately
          show ?thesis
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(3)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            apply (simp add: Let_def)
            unfolding swapWatches_def
            by simp
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"

          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          have "getM ?state'' = getM state 
            getF ?state'' = getF state"
            unfolding swapWatches_def
            unfolding setReason_def
            by simp
          ultimately
          show ?thesis
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(3)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            apply (simp add: Let_def)
            unfolding setReason_def
            unfolding swapWatches_def
            by simp
        qed
      qed
    qed
  next
    case False
    let ?state' = state
    let ?w1 = wa
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch1 state clause = Some wa
      unfolding swapWatches_def
      by auto
    let ?w2 = wb
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch2 state clause = Some wb
      unfolding swapWatches_def
      by auto    
    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True
      thus ?thesis
        using Cons
        using ¬ Some literal = getWatch1 state clause
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹literalTrue ?w1 (elements (getM ?state'))
        by (simp add:Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state')) clause"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by simp

        let ?state'' = "setWatch2 clause l' ?state'"

        from Cons(2)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state')) clause
          unfolding InvariantWatchesEl_def
          unfolding setWatch2_def
          by auto
        moreover
        have "getM ?state'' = getM state 
          getF ?state'' = getF state"
          unfolding setWatch2_def
          by simp
        ultimately
        show ?thesis
          using Cons(1)[of "?state''"]
          using Cons(3)
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ¬ Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using Some
          apply (simp add: Let_def)
          unfolding setWatch2_def
          by simp
      next
        case None
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            by auto
          moreover
          have "getM ?state'' = getM state 
            getF ?state'' = getF state"
            by simp
          ultimately
          show ?thesis
            using Cons(1)[of "?state''"]
            using Cons(3)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ¬ Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            by (simp add: Let_def)
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"
          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding setReason_def
            by auto
          moreover
          have "getM ?state'' = getM state 
            getF ?state'' = getF state"
            unfolding setReason_def
            by simp
          ultimately
          show ?thesis
            using Cons(1)[of "?state''"]
            using Cons(3)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ¬ Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            apply (simp add: Let_def)
            unfolding setReason_def
            by simp
        qed
      qed
    qed
  qed
qed

lemma InvariantWatchesElNotifyWatchesLoop:
fixes literal :: Literal and Wl :: "nat list" and newWl :: "nat list" and state :: State 
assumes 
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  " (c::nat). c  set Wl  0  c  c < length (getF state)"
shows
  "let state' = (notifyWatches_loop literal Wl newWl state) in
     InvariantWatchesEl (getF state') (getWatch1 state') (getWatch2 state')"
using assms
proof (induct Wl arbitrary: newWl state)
  case Nil
  thus ?case
    by simp
next
  case (Cons clause Wl')
  from  (c::nat). c  set (clause # Wl')  0  c  c < length (getF state)
  have "0  clause" and "clause < length (getF state)"
    by auto
  then obtain wa::Literal and wb::Literal
    where "getWatch1 state clause = Some wa" and "getWatch2 state clause = Some wb"
    using Cons
    unfolding InvariantWatchesEl_def
    by auto
  show ?case
  proof (cases "Some literal = getWatch1 state clause")
    case True
    let ?state' = "swapWatches clause state"
    let ?w1 = wb
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch2 state clause = Some wb
      unfolding swapWatches_def
      by auto
    let ?w2 = wa
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch1 state clause = Some wa
      unfolding swapWatches_def
      by auto    
    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True

      from Cons(2)
      have "InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
        unfolding InvariantWatchesEl_def
        unfolding swapWatches_def
        by auto
      moreover
      have "getF ?state' = getF state"
        unfolding swapWatches_def
        by simp
      ultimately
      show ?thesis
        using Cons
        using ‹Some literal = getWatch1 state clause
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹literalTrue ?w1 (elements (getM ?state'))
        by (simp add: Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state') clause)"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by simp

        let ?state'' = "setWatch2 clause l' ?state'"

        from Cons(2)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state') clause)
          unfolding InvariantWatchesEl_def
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        moreover
        have "getF ?state'' = getF state"
          unfolding swapWatches_def
          unfolding setWatch2_def
          by simp
        ultimately
        show ?thesis
          using Cons
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ‹Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using Some
          by (simp add: Let_def)
      next
        case None
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            by auto
          moreover
          have "getF ?state'' = getF state"
            unfolding swapWatches_def
            by simp
          ultimately
          show ?thesis
            using Cons
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            by (simp add: Let_def)
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"

          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          have "getF ?state'' = getF state"
            unfolding swapWatches_def
            unfolding setReason_def
            by simp
          ultimately
          show ?thesis
            using Cons
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            by (simp add: Let_def)
        qed
      qed
    qed
  next
    case False
    let ?state' = state
    let ?w1 = wa
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch1 state clause = Some wa
      unfolding swapWatches_def
      by auto
    let ?w2 = wb
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch2 state clause = Some wb
      unfolding swapWatches_def
      by auto    
    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True
      thus ?thesis
        using Cons
        using ¬ Some literal = getWatch1 state clause
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹literalTrue ?w1 (elements (getM ?state'))
        by (simp add:Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state') clause)"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by simp

        let ?state'' = "setWatch2 clause l' ?state'"

        from Cons
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state') clause)
          unfolding InvariantWatchesEl_def
          unfolding setWatch2_def
          by auto
        moreover
        have "getF ?state'' = getF state"
          unfolding setWatch2_def
          by simp
        ultimately
        show ?thesis
          using Cons
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ¬ Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using Some
          by (simp add: Let_def)
      next
        case None
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            by auto
          moreover
          have "getF ?state'' = getF state"
            by simp
          ultimately
          show ?thesis
            using Cons
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ¬ Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            by (simp add: Let_def)
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"
          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding setReason_def
            by auto
          moreover
          have "getF ?state'' = getF state"
            unfolding setReason_def
            by simp       
          ultimately
          show ?thesis
            using Cons
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ¬ Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            by (simp add: Let_def)
        qed
      qed
    qed
  qed
qed

lemma InvariantWatchesDifferNotifyWatchesLoop:
fixes literal :: Literal and Wl :: "nat list" and newWl :: "nat list" and state :: State 
assumes 
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and 
  " (c::nat). c  set Wl  0  c  c < length (getF state)"
shows
  "let state' = (notifyWatches_loop literal Wl newWl state) in
     InvariantWatchesDiffer (getF state') (getWatch1 state') (getWatch2 state')"
using assms
proof (induct Wl arbitrary: newWl state)
  case Nil
  thus ?case
    by simp
next
  case (Cons clause Wl')
  from  (c::nat). c  set (clause # Wl')  0  c  c < length (getF state)
  have "0  clause" and "clause < length (getF state)"
    by auto
  then obtain wa::Literal and wb::Literal
    where "getWatch1 state clause = Some wa" and "getWatch2 state clause = Some wb"
    using Cons
    unfolding InvariantWatchesEl_def
    by auto
  show ?case
  proof (cases "Some literal = getWatch1 state clause")
    case True
    let ?state' = "swapWatches clause state"
    let ?w1 = wb
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch2 state clause = Some wb
      unfolding swapWatches_def
      by auto
    let ?w2 = wa
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch1 state clause = Some wa
      unfolding swapWatches_def
      by auto    
    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True

      from Cons(2)
      have "InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
        unfolding InvariantWatchesEl_def
        unfolding swapWatches_def
        by auto
      moreover
      from Cons(3)
      have "InvariantWatchesDiffer (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
        unfolding InvariantWatchesDiffer_def
        unfolding swapWatches_def
        by auto
      moreover
      have "getF ?state' = getF state"
        unfolding swapWatches_def
        by simp
      ultimately
      show ?thesis
        using Cons(1)[of "?state'" "clause # newWl"]
        using Cons(4)
        using ‹Some literal = getWatch1 state clause
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹literalTrue ?w1 (elements (getM ?state'))
        by (simp add: Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state') clause)" "l'  literal" "l'  ?w1" "l'  ?w2"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ‹Some literal = getWatch1 state clause
          unfolding swapWatches_def
          by auto

        let ?state'' = "setWatch2 clause l' ?state'"

        from Cons(2)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state') clause)
          unfolding InvariantWatchesEl_def
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        moreover
        from Cons(3)
        have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l'  ?w1
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          unfolding InvariantWatchesDiffer_def
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        moreover
        have "getF ?state'' = getF state"
          unfolding swapWatches_def
          unfolding setWatch2_def
          by simp
        ultimately
        show ?thesis
          using Cons
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ‹Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using Some
          by (simp add: Let_def)
      next
        case None
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            by auto
          moreover
          from Cons(3)
          have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesDiffer_def
            unfolding swapWatches_def
            by auto
          moreover
          have "getF ?state'' = getF state"
            unfolding swapWatches_def
            by simp
          ultimately
          show ?thesis
            using Cons
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            by (simp add: Let_def)
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"

          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          from Cons(3)
          have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesDiffer_def
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          have "getF ?state'' = getF state"
            unfolding swapWatches_def
            unfolding setReason_def
            by simp
          ultimately
          show ?thesis
            using Cons
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            by (simp add: Let_def)
        qed
      qed
    qed
  next
    case False
    let ?state' = state
    let ?w1 = wa
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch1 state clause = Some wa
      unfolding swapWatches_def
      by auto
    let ?w2 = wb
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch2 state clause = Some wb
      unfolding swapWatches_def
      by auto       
    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True
      thus ?thesis
        using Cons
        using ¬ Some literal = getWatch1 state clause
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹literalTrue ?w1 (elements (getM ?state'))
        by (simp add:Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state') clause)" "l'  ?w1" "l'  ?w2"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          unfolding swapWatches_def
          by auto

        let ?state'' = "setWatch2 clause l' ?state'"

        from Cons(2)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state') clause)
          unfolding InvariantWatchesEl_def
          unfolding setWatch2_def
          by auto
        moreover
        from Cons(3)
        have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l'  ?w1
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          unfolding InvariantWatchesDiffer_def
          unfolding setWatch2_def
          by auto
        moreover
        have "getF ?state'' = getF state"
          unfolding setWatch2_def
          by simp
        ultimately
        show ?thesis
          using Cons
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ¬ Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using Some
          by (simp add: Let_def)
      next
        case None
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            by auto
          moreover
          from Cons(3)
          have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesDiffer_def
            by auto
          moreover
          have "getF ?state'' = getF state"
            by simp
          ultimately
          show ?thesis
            using Cons
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ¬ Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            by (simp add: Let_def)
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"

          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding setReason_def
            by auto
          moreover
          from Cons(3)
          have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesDiffer_def
            unfolding setReason_def
            by auto
          moreover
          have "getF ?state'' = getF state"
            unfolding setReason_def
            by simp       
          ultimately
          show ?thesis
            using Cons
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ¬ Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            by (simp add: Let_def)
        qed
      qed
    qed
  qed
qed


lemma InvariantWatchListsContainOnlyClausesFromFNotifyWatchesLoop:
fixes literal :: Literal and Wl :: "nat list" and newWl :: "nat list" and state :: State 
assumes 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and 
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  " (c::nat). c  set Wl  c  set newWl  0  c  c < length (getF state)"
shows
  "let state' = (notifyWatches_loop literal Wl newWl state) in
     InvariantWatchListsContainOnlyClausesFromF (getWatchList state') (getF state')"
using assms
proof (induct Wl arbitrary: newWl state)
  case Nil
  thus ?case
    unfolding InvariantWatchListsContainOnlyClausesFromF_def
    by simp
next
  case (Cons clause Wl')
  from c. c  set (clause # Wl')  c  set newWl  0  c  c < length (getF state)
  have "0  clause" and "clause < length (getF state)"
    by auto
  then obtain wa::Literal and wb::Literal
    where "getWatch1 state clause = Some wa" and "getWatch2 state clause = Some wb"
    using Cons
    unfolding InvariantWatchesEl_def
    by auto
  show ?case
  proof (cases "Some literal = getWatch1 state clause")
    case True
    let ?state' = "swapWatches clause state"
    let ?w1 = wb
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch2 state clause = Some wb
      unfolding swapWatches_def
      by auto
    let ?w2 = wa
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch1 state clause = Some wa
      unfolding swapWatches_def
      by auto    
    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True

      from Cons(2)
      have "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state') (getF ?state')"
        unfolding swapWatches_def
        by auto
      moreover
      from Cons(3)
      have "InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
        unfolding InvariantWatchesEl_def
        unfolding swapWatches_def
        by auto
      moreover
      have "(getF state) = (getF ?state')"
        unfolding swapWatches_def
        by simp
      ultimately
      show ?thesis
        using Cons
        using ‹Some literal = getWatch1 state clause
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹literalTrue ?w1 (elements (getM ?state'))
        by (simp add: Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state') clause)"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by simp

        let ?state'' = "setWatch2 clause l' ?state'"

        from Cons(2)
        have "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state'') (getF ?state'')"
          using clause < length (getF state)
          unfolding InvariantWatchListsContainOnlyClausesFromF_def
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        moreover
        from Cons(3)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state') clause)
          unfolding InvariantWatchesEl_def
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        moreover
        have "(getF state) = (getF ?state'')"
          unfolding swapWatches_def
          unfolding setWatch2_def
          by simp
        ultimately
        show ?thesis
          using Cons
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ‹Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using Some
          by (simp add: Let_def)
      next
        case None
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons(2)
          have "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state'') (getF ?state'')"
            unfolding swapWatches_def
            by auto
          moreover
          from Cons(3)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            by auto
          moreover 
          have "(getF state) = (getF ?state'')"
            unfolding swapWatches_def
            by simp
          ultimately
          show ?thesis
            using Cons
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            by (simp add: Let_def)
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"

          from Cons(2)
          have "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state'') (getF ?state'')"
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          from Cons(3)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          have "(getF state) = (getF ?state'')"
            unfolding swapWatches_def
            unfolding setReason_def
            by simp
          ultimately
          show ?thesis
            using Cons
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            by (simp add: Let_def)
        qed
      qed
    qed
  next
    case False
    let ?state' = state
    let ?w1 = wa
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch1 state clause = Some wa
      unfolding swapWatches_def
      by auto
    let ?w2 = wb
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch2 state clause = Some wb
      unfolding swapWatches_def
      by auto    
    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True
      thus ?thesis
        using Cons
        using ¬ Some literal = getWatch1 state clause
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹literalTrue ?w1 (elements (getM ?state'))
        by (simp add:Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state') clause)"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by simp

        let ?state'' = "setWatch2 clause l' ?state'"

        from Cons(2)
        have "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state'') (getF ?state'')"
          using clause < length (getF state)
          unfolding setWatch2_def
          unfolding InvariantWatchListsContainOnlyClausesFromF_def
          by auto
        moreover 
        from Cons(3)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state') clause)
          unfolding InvariantWatchesEl_def
          unfolding setWatch2_def
          by auto
        moreover
        have "(getF state) = (getF ?state'')"
          unfolding setWatch2_def
          by simp
        ultimately
        show ?thesis
          using Cons
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ¬ Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using Some
          by (simp add: Let_def)
      next
        case None
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons(3)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            by auto
          moreover
          have "getF ?state'' = getF state"
            by simp
          ultimately
          show ?thesis
            using Cons
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ¬ Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            by (simp add: Let_def)
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"

          from Cons(2)
          have "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state'') (getF ?state'')"
            unfolding setReason_def
            by auto
          moreover
          from Cons(3)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding setReason_def
            by auto
          moreover
          have "getF ?state'' = getF state"
            unfolding setReason_def
            by simp
          ultimately
          show ?thesis
            using Cons
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ¬ Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            by (simp add: Let_def)
        qed
      qed
    qed
  qed
qed

lemma InvariantWatchListsCharacterizationNotifyWatchesLoop:
  fixes literal :: Literal and Wl :: "nat list" and newWl :: "nat list" and state :: State 
  assumes 
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchListsUniq (getWatchList state)"
  " (c::nat). c  set Wl  0  c  c < length (getF state)"
  " (c::nat) (l::Literal). l  literal 
             (c  set (getWatchList state l)) = (Some l = getWatch1 state c  Some l = getWatch2 state c)"
  " (c::nat). (c  set newWl  c  set Wl) = (Some literal = (getWatch1 state c)  Some literal = (getWatch2 state c))"
  "set Wl  set newWl = {}"
  "uniq Wl"
  "uniq newWl"
  shows
  "let state' = (notifyWatches_loop literal Wl newWl state) in
     InvariantWatchListsCharacterization (getWatchList state') (getWatch1 state') (getWatch2 state') 
     InvariantWatchListsUniq (getWatchList state')"
using assms
proof (induct Wl arbitrary: newWl state)
  case Nil
  thus ?case
    unfolding InvariantWatchListsCharacterization_def
    unfolding InvariantWatchListsUniq_def
    by simp
next
  case (Cons clause Wl')
  from ‹uniq (clause # Wl')
  have "clause  set Wl'"
    by (simp add:uniqAppendIff)

  have "set Wl'  set (clause # newWl) = {}"
    using Cons(8)
    using clause  set Wl'
    by simp

  have "uniq Wl'"
    using Cons(9)
    using uniqAppendIff
    by simp
  
  have "uniq (clause # newWl)"
    using Cons(10) Cons(8)
    using uniqAppendIff
    by force

  from c. c  set (clause # Wl')  0  c  c < length (getF state)
  have "0  clause" and "clause < length (getF state)"
    by auto
  then obtain wa::Literal and wb::Literal
    where "getWatch1 state clause = Some wa" and "getWatch2 state clause = Some wb"
    using Cons
    unfolding InvariantWatchesEl_def
    by auto
  show ?case
  proof (cases "Some literal = getWatch1 state clause")
    case True
    let ?state' = "swapWatches clause state"
    let ?w1 = wb
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch2 state clause = Some wb
      unfolding swapWatches_def
      by auto
    let ?w2 = wa
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch1 state clause = Some wa
      unfolding swapWatches_def
      by auto
    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True
      
      from Cons(2)
      have "InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
        unfolding InvariantWatchesEl_def
        unfolding swapWatches_def
        by auto
      moreover
      from Cons(3)
      have "InvariantWatchesDiffer (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
        unfolding InvariantWatchesDiffer_def
        unfolding swapWatches_def
        by auto
      moreover
      from Cons(4)
      have "InvariantWatchListsUniq (getWatchList ?state')"
        unfolding InvariantWatchListsUniq_def
        unfolding swapWatches_def
        by auto
      moreover
      have "(getF ?state') = (getF state)" and "(getWatchList ?state') = (getWatchList state)"
        unfolding swapWatches_def
        by auto
      moreover 
      have "c l. l  literal 
        (c  set (getWatchList ?state' l)) =
        (Some l = getWatch1 ?state' c  Some l = getWatch2 ?state' c)"
        using Cons(6)
        using (getWatchList ?state') = (getWatchList state)
        using swapWatchesEffect
        by auto
      moreover 
      have "c. (c  set (clause # newWl)  c  set Wl') =
        (Some literal = getWatch1 ?state' c  Some literal = getWatch2 ?state' c)"
        using Cons(7)
        using swapWatchesEffect
        by auto
      ultimately
      show ?thesis
        using Cons(1)[of "?state'" "clause # newWl"]
        using Cons(5)
        using ‹Some literal = getWatch1 state clause
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹literalTrue ?w1 (elements (getM ?state'))
        using ‹uniq Wl'
        using ‹uniq (clause # newWl)
        using ‹set Wl'  set (clause # newWl) = {}
        by (simp add: Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state') clause)" "l'  literal" "l'  ?w1" "l'  ?w2"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ‹Some literal = getWatch1 state clause
          unfolding swapWatches_def
          by auto
        
        let ?state'' = "setWatch2 clause l' ?state'"
        
        from Cons(2)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state') clause)
          unfolding InvariantWatchesEl_def
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        moreover
        from Cons(3)
        have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using ‹getWatch1 ?state' clause = Some ?w1
          using l'  ?w1
          unfolding InvariantWatchesDiffer_def
          unfolding swapWatches_def
          unfolding setWatch2_def
          by simp
        moreover
        have "clause  set (getWatchList state l')"
          using l'  literal
          using l'  ?w1 l'  ?w2
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using Cons(6)
          unfolding swapWatches_def
          by simp
        with Cons(4)
        have "InvariantWatchListsUniq (getWatchList ?state'')"
          unfolding InvariantWatchListsUniq_def
          unfolding swapWatches_def
          unfolding setWatch2_def
          using uniqAppendIff
          by force
        moreover
        have "(getF ?state'') = (getF state)" and 
          "(getWatchList ?state'') = (getWatchList state)(l' := clause # (getWatchList state l'))"
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        moreover 
        have "c l. l  literal 
          (c  set (getWatchList ?state'' l)) =
          (Some l = getWatch1 ?state'' c  Some l = getWatch2 ?state'' c)"
        proof-
          {
            fix c::nat and l::Literal
            assume "l  literal"
            have "(c  set (getWatchList ?state'' l)) = (Some l = getWatch1 ?state'' c  Some l = getWatch2 ?state'' c)"
            proof (cases "c = clause")
              case True
              show ?thesis
              proof (cases "l = l'")
                case True
                thus ?thesis
                  using c = clause
                  unfolding setWatch2_def
                  by simp
              next
                case False
                show ?thesis
                  using Cons(6)
                  using (getWatchList ?state'') = (getWatchList state)(l' := clause # (getWatchList state l'))
                  using l  l'
                  using l  literal
                  using ‹getWatch1 ?state' clause = Some ?w1
                  using ‹getWatch2 ?state' clause = Some ?w2
                  using ‹Some literal = getWatch1 state clause
                  using c = clause
                  using swapWatchesEffect
                  unfolding swapWatches_def
                  unfolding setWatch2_def
                  by simp
              qed
            next
              case False
              thus ?thesis
                using Cons(6)
                using l  literal
                using (getWatchList ?state'') = (getWatchList state)(l' := clause # (getWatchList state l'))
                using c  clause
                unfolding setWatch2_def
                using swapWatchesEffect[of "clause" "state" "c"]
                by auto
            qed
          }
          thus ?thesis
            by simp
        qed
        moreover
        have "c. (c  set newWl  c  set Wl') =
          (Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c)"
        proof-
          show ?thesis
          proof
            fix c :: nat
            show "(c  set newWl  c  set Wl') =
              (Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c)"
            proof
              assume "c  set newWl  c  set Wl'"
              show "Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c"
              proof-
                from c  set newWl  c  set Wl'
                have "Some literal = getWatch1 state c  Some literal = getWatch2 state c"
                  using Cons(7)
                  by auto
                
                from Cons(8) clause  set Wl' c  set newWl  c  set Wl'
                have "c  clause"
                  by auto
                
                show ?thesis
                  using ‹Some literal = getWatch1 state c  Some literal = getWatch2 state c
                  using c  clause
                  using swapWatchesEffect
                  unfolding setWatch2_def
                  by simp
              qed
            next
              assume "Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c"
              show "c  set newWl  c  set Wl'"
              proof-
                have "Some literal  getWatch1 ?state'' clause   Some literal  getWatch2 ?state'' clause"
                  using l'  literal
                  using clause < length (getF state)
                  using ‹InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)
                  using ‹getWatch1 ?state' clause = Some ?w1
                  using ‹getWatch2 ?state' clause = Some ?w2
                  using ‹Some literal = getWatch1 state clause
                  unfolding InvariantWatchesDiffer_def
                  unfolding setWatch2_def
                  unfolding swapWatches_def
                  by auto
                thus ?thesis
                  using ‹Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c
                  using Cons(7)
                  using swapWatchesEffect
                  unfolding setWatch2_def
                  by (auto split: if_split_asm)
              qed
            qed
          qed
        qed
        moreover
        have "c. (c  set (clause # newWl)  c  set Wl') =
          (Some literal = getWatch1 ?state' c  Some literal = getWatch2 ?state' c)"
          using Cons(7)
          using swapWatchesEffect
          by auto
        ultimately
        show ?thesis
          using Cons(1)[of "?state''" "newWl"]
          using Cons(5)
          using ‹uniq Wl'
          using ‹uniq newWl
          using ‹set Wl'  set (clause # newWl) = {}
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ‹Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using Some
          by (simp add: Let_def fun_upd_def)
      next
        case None
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            by auto
          moreover
          from Cons(3)
          have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesDiffer_def
            unfolding swapWatches_def
            by auto
          moreover
          from Cons(4)
          have "InvariantWatchListsUniq (getWatchList ?state'')"
            unfolding InvariantWatchListsUniq_def
            unfolding swapWatches_def
            by auto
          moreover 
          have "(getF state) = (getF ?state'')" and "(getWatchList state) = (getWatchList ?state'')" 
            unfolding swapWatches_def
            by auto
          moreover
          have "c l. l  literal 
            (c  set (getWatchList ?state'' l)) =
            (Some l = getWatch1 ?state'' c  Some l = getWatch2 ?state'' c)"
            using Cons(6)
            using (getWatchList state) = (getWatchList ?state'')
            using swapWatchesEffect
            by auto
          moreover 
          have "c. (c  set (clause # newWl)  c  set Wl') =
            (Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c)"
            using Cons(7)
            using swapWatchesEffect
            by auto
          ultimately
          show ?thesis
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(5)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            using ‹uniq Wl'
            using ‹uniq (clause # newWl)
            using ‹set Wl'  set (clause # newWl) = {}
            by (simp add: Let_def)
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"

          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          from Cons(3)
          have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesDiffer_def
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          from Cons(4)
          have "InvariantWatchListsUniq (getWatchList ?state'')"
            unfolding InvariantWatchListsUniq_def
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover 
          have "(getF state) = (getF ?state'')" and "(getWatchList state) = (getWatchList ?state'')" 
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          have "c l. l  literal 
            (c  set (getWatchList ?state'' l)) =
            (Some l = getWatch1 ?state'' c  Some l = getWatch2 ?state'' c)"
            using Cons(6)
            using (getWatchList state) = (getWatchList ?state'')
            using swapWatchesEffect
            unfolding setReason_def
            by auto
          moreover 
          have "c. (c  set (clause # newWl)  c  set Wl') =
            (Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c)"
            using Cons(7)
            using swapWatchesEffect
            unfolding setReason_def
            by auto
          ultimately
          show ?thesis
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(5)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            using ‹uniq Wl'
            using ‹uniq (clause # newWl)
            using ‹set Wl'  set (clause # newWl) = {}
            by (simp add: Let_def)
        qed
      qed
    qed
  next
    case False
    let ?state' = state
    let ?w1 = wa
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch1 state clause = Some wa
      unfolding swapWatches_def
      by auto
    let ?w2 = wb
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch2 state clause = Some wb
      unfolding swapWatches_def
      by auto    

    have "Some literal = getWatch2 state clause"
      using ‹getWatch1 ?state' clause = Some ?w1
      using ‹getWatch2 ?state' clause = Some ?w2
      using ‹Some literal  getWatch1 state clause
      using Cons(7)
      by force

    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True
      from Cons(7) have
        "c. (c  set (clause # newWl)  c  set Wl') =
        (Some literal = getWatch1 state c  Some literal = getWatch2 state c)"
        by auto
      thus ?thesis
        using Cons(1)[of "?state'" "clause # newWl"]
        using Cons(2) Cons(3) Cons(4) Cons(5) Cons(6)
        using ¬ Some literal = getWatch1 state clause
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹literalTrue ?w1 (elements (getM ?state'))
        using ‹uniq (clause # newWl)
        using ‹uniq Wl'
        using ‹set Wl'  set (clause # newWl) = {}
        by simp
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state') clause)" "l'  literal" "l'  ?w1" "l'  ?w2"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          using ‹Some literal = getWatch2 state clause
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          by auto

        let ?state'' = "setWatch2 clause l' ?state'"

        from Cons(2)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state') clause)
          unfolding InvariantWatchesEl_def
          unfolding setWatch2_def
          by auto
        moreover
        from Cons(3)
        have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using ‹getWatch1 ?state' clause = Some ?w1
          using l'  ?w1
          unfolding InvariantWatchesDiffer_def
          unfolding setWatch2_def
          by simp
        moreover
        have "clause  set (getWatchList state l')"
          using l'  literal
          using l'  ?w1 l'  ?w2
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using Cons(6)
          by simp
        with Cons(4)
        have "InvariantWatchListsUniq (getWatchList ?state'')"
          unfolding InvariantWatchListsUniq_def
          unfolding setWatch2_def
          using uniqAppendIff
          by force
        moreover
        have "(getF ?state'') = (getF state)" and 
          "(getWatchList ?state'') = (getWatchList state)(l' := clause # (getWatchList state l'))"
          unfolding setWatch2_def
          by auto
        moreover 
        have "c l. l  literal 
          (c  set (getWatchList ?state'' l)) =
          (Some l = getWatch1 ?state'' c  Some l = getWatch2 ?state'' c)"
        proof-
          {
            fix c::nat and l::Literal
            assume "l  literal"
            have "(c  set (getWatchList ?state'' l)) = (Some l = getWatch1 ?state'' c  Some l = getWatch2 ?state'' c)"
            proof (cases "c = clause")
              case True
              show ?thesis
              proof (cases "l = l'")
                case True
                thus ?thesis
                  using c = clause
                  unfolding setWatch2_def
                  by simp
              next
                case False
                show ?thesis
                  using Cons(6)
                  using (getWatchList ?state'') = (getWatchList state)(l' := clause # (getWatchList state l'))
                  using l  l'
                  using l  literal
                  using ‹getWatch1 ?state' clause = Some ?w1
                  using ‹getWatch2 ?state' clause = Some ?w2
                  using ‹Some literal = getWatch2 state clause
                  using c = clause
                  unfolding setWatch2_def
                  by simp
              qed
            next
              case False
              thus ?thesis
                using Cons(6)
                using l  literal
                using (getWatchList ?state'') = (getWatchList state)(l' := clause # (getWatchList state l'))
                using c  clause
                unfolding setWatch2_def
                by auto
            qed
          }
          thus ?thesis
            by simp
        qed
        moreover
        have "c. (c  set newWl  c  set Wl') =
          (Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c)"
        proof-
          show ?thesis
          proof
            fix c :: nat
            show "(c  set newWl  c  set Wl') =
              (Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c)"
            proof
              assume "c  set newWl  c  set Wl'"
              show "Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c"
              proof-
                from c  set newWl  c  set Wl'
                have "Some literal = getWatch1 state c  Some literal = getWatch2 state c"
                  using Cons(7)
                  by auto
                
                from Cons(8) clause  set Wl' c  set newWl  c  set Wl'
                have "c  clause"
                  by auto
                
                show ?thesis
                  using ‹Some literal = getWatch1 state c  Some literal = getWatch2 state c
                  using c  clause
                  unfolding setWatch2_def
                  by simp
              qed
            next
              assume "Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c"
              show "c  set newWl  c  set Wl'"
              proof-
                have "Some literal  getWatch1 ?state'' clause   Some literal  getWatch2 ?state'' clause"
                  using l'  literal
                  using clause < length (getF state)
                  using ‹InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)
                  using ‹getWatch1 ?state' clause = Some ?w1
                  using ‹getWatch2 ?state' clause = Some ?w2
                  using ‹Some literal = getWatch2 state clause
                  unfolding InvariantWatchesDiffer_def
                  unfolding setWatch2_def
                  by auto
                thus ?thesis
                  using ‹Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c
                  using Cons(7)
                  unfolding setWatch2_def
                  by (auto split: if_split_asm)
              qed
            qed
          qed
        qed
        moreover
        have "c. (c  set (clause # newWl)  c  set Wl') =
          (Some literal = getWatch1 ?state' c  Some literal = getWatch2 ?state' c)"
          using Cons(7)
          by auto
        ultimately
        show ?thesis
          using Cons(1)[of "?state''" "newWl"]
          using Cons(5)
          using ‹uniq Wl'
          using ‹uniq newWl
          using ‹set Wl'  set (clause # newWl) = {}
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ¬ Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using Some
          by (simp add: Let_def fun_upd_def)
      next
        case None
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            by auto
          moreover
          from Cons(3)
          have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesDiffer_def
            by auto
          moreover
          from Cons(4)
          have "InvariantWatchListsUniq (getWatchList ?state'')"
            unfolding InvariantWatchListsUniq_def
            by auto
          moreover 
          have "(getF state) = (getF ?state'')"
            by auto
          moreover
          have "c l. l  literal 
            (c  set (getWatchList ?state'' l)) =
            (Some l = getWatch1 ?state'' c  Some l = getWatch2 ?state'' c)"
            using Cons(6)
            by simp
          moreover 
          have "c. (c  set (clause # newWl)  c  set Wl') =
            (Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c)"
            using Cons(7)
            by auto
          ultimately
          have "let state' = notifyWatches_loop literal Wl' (clause # newWl) ?state'' in 
                      InvariantWatchListsCharacterization (getWatchList state') (getWatch1 state') (getWatch2 state') 
                      InvariantWatchListsUniq (getWatchList state')"
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(5)
            using ‹uniq Wl'
            using ‹uniq (clause # newWl)
            using ‹set Wl'  set (clause # newWl) = {}
            apply (simp only: Let_def)
            by (simp (no_asm_use)) (simp)
          thus ?thesis
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal   getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            by (simp add: Let_def)
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"


          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding setReason_def
            by auto
          moreover
          from Cons(3)
          have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesDiffer_def
            unfolding setReason_def
            by auto
          moreover
          from Cons(4)
          have "InvariantWatchListsUniq (getWatchList ?state'')"
            unfolding InvariantWatchListsUniq_def
            unfolding setReason_def
            by auto
          moreover 
          have "(getF state) = (getF ?state'')"
            unfolding setReason_def
            by auto
          moreover
          have "c l. l  literal 
            (c  set (getWatchList ?state'' l)) =
            (Some l = getWatch1 ?state'' c  Some l = getWatch2 ?state'' c)"
            using Cons(6)
            unfolding setReason_def
            by auto
          moreover 
          have "c. (c  set (clause # newWl)  c  set Wl') =
            (Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c)"
            using Cons(7)
            unfolding setReason_def
            by auto
          ultimately
          show ?thesis
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(5)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ¬ Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            using ‹uniq Wl'
            using ‹uniq (clause # newWl)
            using ‹set Wl'  set (clause # newWl) = {}
            by (simp add: Let_def)
        qed
      qed
    qed
  qed
qed

lemma NotifyWatchesLoopWatchCharacterizationEffect:
fixes literal :: Literal and Wl :: "nat list" and newWl :: "nat list" and state :: State
assumes 
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantConsistent (getM state)" and
  "InvariantUniq (getM state)" and
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) M"
  " (c::nat). c  set Wl  0  c  c < length (getF state)" and
  "getM state = M @ [(opposite literal, decision)]"
  "uniq Wl"
  "  (c::nat). c  set Wl  Some literal = (getWatch1 state c)   Some literal = (getWatch2 state c)"

shows
  "let state' = notifyWatches_loop literal Wl newWl state in
      (c::nat). c  set Wl  ( w1 w2.(Some w1 = (getWatch1 state' c)  Some w2 = (getWatch2 state' c))  
      (watchCharacterizationCondition w1 w2 (getM state') (nth (getF state') c)   
       watchCharacterizationCondition w2 w1 (getM state') (nth (getF state') c))
     )"
using assms
proof (induct Wl arbitrary: newWl state)
  case Nil
  thus ?case
    by simp
next
  case (Cons clause Wl')
  from  (c::nat). c  set (clause # Wl')  0  c  c < length (getF state)
  have "0  clause  clause < length (getF state)"
    by auto
  then obtain wa::Literal and wb::Literal
    where "getWatch1 state clause = Some wa" and "getWatch2 state clause = Some wb"
    using Cons
    unfolding InvariantWatchesEl_def
    by auto
  have "uniq Wl'" "clause  set Wl'"
    using Cons(9)
    by (auto simp add: uniqAppendIff)
  show ?case
  proof (cases "Some literal = getWatch1 state clause")
    case True
    let ?state' = "swapWatches clause state"
    let ?w1 = wb
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch2 state clause = Some wb
      unfolding swapWatches_def
      by auto
    let ?w2 = wa
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch1 state clause = Some wa
      unfolding swapWatches_def
      by auto
    with True have
      "?w2 = literal"
      unfolding swapWatches_def
      by simp

    from ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)
    have "?w1 el (nth (getF state) clause)" "?w2 el (nth (getF state) clause)"
      using ‹getWatch1 ?state' clause = Some ?w1
      using ‹getWatch2 ?state' clause = Some ?w2
      using 0  clause  clause < length (getF state)
      unfolding InvariantWatchesEl_def
      unfolding swapWatches_def
      by auto

    from ‹InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)
    have "?w1  ?w2"
      using ‹getWatch1 ?state' clause = Some ?w1
      using ‹getWatch2 ?state' clause = Some ?w2
      using 0  clause  clause < length (getF state)
      unfolding InvariantWatchesDiffer_def
      unfolding swapWatches_def
      by auto

    have "¬ literalFalse ?w2 (elements M)"
      using ?w2 = literal
      using Cons(5)
      using Cons(8)
      unfolding InvariantUniq_def
      by (simp add: uniqAppendIff)

    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True

      let ?fState = "notifyWatches_loop literal Wl' (clause # newWl) ?state'"

      from Cons(2)
      have "InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
        unfolding InvariantWatchesEl_def
        unfolding swapWatches_def
        by auto
      moreover
      from Cons(3)
      have "InvariantWatchesDiffer (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
        unfolding InvariantWatchesDiffer_def
        unfolding swapWatches_def
        by auto
      moreover
      from Cons(4)
      have "InvariantConsistent (getM ?state')"
        unfolding InvariantConsistent_def
        unfolding swapWatches_def
        by simp
      moreover
      from Cons(5)
      have "InvariantUniq (getM ?state')"
        unfolding InvariantUniq_def
        unfolding swapWatches_def
        by simp
      moreover
      from Cons(6)
      have "InvariantWatchCharacterization (getF ?state') (getWatch1 ?state') (getWatch2 ?state') M"
        unfolding swapWatches_def
        unfolding InvariantWatchCharacterization_def
        unfolding watchCharacterizationCondition_def
        by simp
      moreover
      have "getM ?state' = getM state"
        "getF ?state' = getF state"
        unfolding swapWatches_def
        by auto
      moreover 
      have "  (c::nat). c  set Wl'  Some literal = (getWatch1 ?state' c)   Some literal = (getWatch2 ?state' c)"
        using Cons(10)
        unfolding swapWatches_def
        by auto
      moreover
      have "getWatch1 ?fState clause = getWatch1 ?state' clause  getWatch2 ?fState clause = getWatch2 ?state' clause"
        using clause  set Wl'
        using ‹InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state') ‹getF ?state' = getF state
        using Cons(7)
        using notifyWatchesLoopPreservedWatches[of "?state'" "Wl'" "literal" "clause # newWl" ]
        by (simp add: Let_def)
      moreover
      have "watchCharacterizationCondition ?w1 ?w2 (getM ?fState) (getF ?fState ! clause) 
            watchCharacterizationCondition ?w2 ?w1 (getM ?fState) (getF ?fState ! clause)"
      proof-
        have "(getM ?fState) = (getM state)  (getF ?fState = getF state)"
          using notifyWatchesLoopPreservedVariables[of "?state'" "Wl'" "literal" "clause # newWl"]
          using ‹InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state') ‹getF ?state' = getF state
          using Cons(7)
          unfolding swapWatches_def
          by (simp add: Let_def)
        moreover
        have "¬ literalFalse ?w1 (elements M)"
          using ‹literalTrue ?w1 (elements (getM ?state')) ?w1  ?w2 ?w2 = literal
          using Cons(4) Cons(8)
          unfolding InvariantConsistent_def
          unfolding swapWatches_def
          by (auto simp add: inconsistentCharacterization)
        moreover 
        have "elementLevel (opposite ?w2) (getM ?state') = currentLevel (getM ?state')"
          using ?w2 = literal
          using Cons(5) Cons(8)
          unfolding InvariantUniq_def
          unfolding swapWatches_def
          by (auto simp add: uniqAppendIff elementOnCurrentLevel)
        ultimately
        show ?thesis
          using ‹getWatch1 ?fState clause = getWatch1 ?state' clause  getWatch2 ?fState clause = getWatch2 ?state' clause
          using ?w2 = literal ?w1  ?w2
          using ?w1 el (nth (getF state) clause)
          using ‹literalTrue ?w1 (elements (getM ?state'))
          unfolding watchCharacterizationCondition_def
          using elementLevelLeqCurrentLevel[of "?w1" "getM ?state'"]
          using notifyWatchesLoopPreservedVariables[of "?state'" "Wl'" "literal" "clause # newWl"]
          using ‹InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state') ‹getF ?state' = getF state
          using Cons(7) 
          using Cons(8)
          unfolding swapWatches_def
          by (auto simp add: Let_def)
      qed
      ultimately
      show ?thesis
        using Cons(1)[of "?state'" "clause # newWl"]
        using Cons(7) Cons(8)
        using ‹uniq Wl'
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹Some literal = getWatch1 state clause
        using ‹literalTrue ?w1 (elements (getM ?state'))
        by (simp add: Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state') clause)" "l'  ?w1" "l'  ?w2" "¬ literalFalse l' (elements (getM ?state'))"
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by auto

        let ?state'' = "setWatch2 clause l' ?state'"
        let ?fState = "notifyWatches_loop literal Wl' newWl ?state''"

        from Cons(2)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state') clause)
          unfolding InvariantWatchesEl_def
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        moreover
        from Cons(3)
        have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l'  ?w1
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          unfolding InvariantWatchesDiffer_def
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        moreover
        from Cons(4)
        have "InvariantConsistent (getM ?state'')"
          unfolding InvariantConsistent_def
          unfolding setWatch2_def
          unfolding swapWatches_def
          by simp
        moreover
        from Cons(5)
        have "InvariantUniq (getM ?state'')"
          unfolding InvariantUniq_def
          unfolding setWatch2_def
          unfolding swapWatches_def
          by simp
        moreover
        have "InvariantWatchCharacterization (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') M"
        proof-
          {
            fix c::nat and ww1::Literal and ww2::Literal
            assume a: "0  c  c < length (getF ?state'')  Some ww1 = (getWatch1 ?state'' c)  Some ww2 = (getWatch2 ?state'' c)"
            assume b: "literalFalse ww1 (elements M)"
              
            have "(l. l el ((getF ?state'') ! c)  literalTrue l (elements M)  elementLevel l M  elementLevel (opposite ww1) M) 
                  (l. l el ((getF ?state'') ! c)  l  ww1  l  ww2  
                       literalFalse l (elements M)  elementLevel (opposite l) M  elementLevel (opposite ww1) M)"
            proof (cases "c = clause")
              case False
              thus ?thesis
                using a and b
                using Cons(6)
                unfolding InvariantWatchCharacterization_def
                unfolding watchCharacterizationCondition_def
                unfolding swapWatches_def
                unfolding setWatch2_def
                by simp
            next
              case True
              with a 
              have "ww1 = ?w1" and "ww2 = l'"
                using ‹getWatch1 ?state' clause = Some ?w1
                using ‹getWatch2 ?state' clause = Some ?w2[THEN sym]
                unfolding setWatch2_def
                unfolding swapWatches_def
                by auto
              
              have "¬ (l. l el (getF state ! clause)  l  ?w1  l  ?w2  literalFalse l (elements M))"
                using Cons(8)
                using l'  ?w1 and l'  ?w2 l' el (nth (getF ?state') clause)
                using ¬ literalFalse l' (elements (getM ?state'))
                using a and b
                using c = clause
                unfolding swapWatches_def
                unfolding setWatch2_def
                by auto
              moreover
              have "(l. l el (getF state ! clause)  literalTrue l (elements M)  
                elementLevel l M  elementLevel (opposite ?w1) M) 
                (l. l el (getF state ! clause)  l  ?w1  l  ?w2  literalFalse l (elements M))"
                using Cons(6)
                unfolding InvariantWatchCharacterization_def
                unfolding watchCharacterizationCondition_def
                using 0  clause  clause < length (getF state)
                using ‹getWatch1 ?state' clause = Some ?w1[THEN sym]
                using ‹getWatch2 ?state' clause = Some ?w2[THEN sym]
                using ‹literalFalse ww1 (elements M)
                using ww1 = ?w1
                unfolding setWatch2_def
                unfolding swapWatches_def
                by auto
              ultimately
              show ?thesis
                using ww1 = ?w1
                using c = clause
                unfolding setWatch2_def
                unfolding swapWatches_def
                by auto
            qed
          }
          moreover 
          {
            fix c::nat and ww1::Literal and ww2::Literal
            assume a: "0  c  c < length (getF ?state'')  Some ww1 = (getWatch1 ?state'' c)  Some ww2 = (getWatch2 ?state'' c)"
            assume b: "literalFalse ww2 (elements M)"
            
            have "(l. l el ((getF ?state'') ! c)  literalTrue l (elements M)  elementLevel l M  elementLevel (opposite ww2) M) 
                  (l. l el ((getF ?state'') ! c)  l  ww1  l  ww2  
                       literalFalse l (elements M)  elementLevel (opposite l) M  elementLevel (opposite ww2) M)"
            proof (cases "c = clause")
              case False
              thus ?thesis
                using a and b
                using Cons(6)
                unfolding InvariantWatchCharacterization_def
                unfolding watchCharacterizationCondition_def
                unfolding swapWatches_def
                unfolding setWatch2_def
                by auto
            next
              case True
              with a 
              have "ww1 = ?w1" and "ww2 = l'"
                using ‹getWatch1 ?state' clause = Some ?w1
                using ‹getWatch2 ?state' clause = Some ?w2[THEN sym]
                unfolding setWatch2_def
                unfolding swapWatches_def
                by auto
              with ¬ literalFalse l' (elements (getM ?state')) b
                Cons(8)
              have False
                unfolding swapWatches_def
                by simp
              thus ?thesis
                by simp
            qed
          }
          ultimately
          show ?thesis
            unfolding InvariantWatchCharacterization_def
            unfolding watchCharacterizationCondition_def
            by blast
        qed
        moreover 
        have "  (c::nat). c  set Wl'  Some literal = (getWatch1 ?state'' c)   Some literal = (getWatch2 ?state'' c)"
          using Cons(10)
          using clause  set Wl'
          using swapWatchesEffect[of "clause" "state"]
          unfolding setWatch2_def
          by simp
        moreover
        have "getM ?state'' = getM state"
          "getF ?state'' = getF state"
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        moreover
        have "getWatch1 ?state'' clause = Some ?w1" "getWatch2 ?state'' clause = Some l'"
          using ‹getWatch1 ?state' clause = Some ?w1
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        hence "getWatch1 ?fState clause = getWatch1 ?state'' clause  getWatch2 ?fState clause = Some l'"
          using clause  set Wl'
          using ‹InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') ‹getF ?state'' = getF state
          using Cons(7)
          using notifyWatchesLoopPreservedWatches[of "?state''" "Wl'" "literal" "newWl"]
          by (simp add: Let_def)
        moreover
        have "watchCharacterizationCondition ?w1 l' (getM ?fState) (getF ?fState ! clause) 
          watchCharacterizationCondition l' ?w1 (getM ?fState) (getF ?fState ! clause)"
        proof-
          have "(getM ?fState) = (getM state)" "(getF ?fState) = (getF state)"
            using notifyWatchesLoopPreservedVariables[of "?state''" "Wl'" "literal" "newWl"]
            using ‹InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') ‹getF ?state'' = getF state
            using Cons(7)
            unfolding setWatch2_def
            unfolding swapWatches_def
            by (auto simp add: Let_def)
          
          have "literalFalse ?w1 (elements M)  
            ( l. l el (nth (getF ?state'') clause)  literalTrue l (elements M)   elementLevel l M  elementLevel (opposite ?w1) M)"
          proof
            assume "literalFalse ?w1 (elements M)"
            show " l. l el (nth (getF ?state'') clause)  literalTrue l (elements M)   elementLevel l M  elementLevel (opposite ?w1) M"
            proof-
              have "¬ ( l. l el (nth (getF state) clause)  l  ?w1  l  ?w2  literalFalse l (elements M))"
                using l' el (nth (getF ?state') clause) l'  ?w1 l'  ?w2 ¬ literalFalse l' (elements (getM ?state'))
                using Cons(8)
                unfolding swapWatches_def
                by auto

              from ‹literalFalse ?w1 (elements M) Cons(6)
              have
                "(l. l el (getF state ! clause)  literalTrue l (elements M)  elementLevel l M  elementLevel (opposite ?w1) M) 
                 (l. l el (getF state ! clause)  l  ?w1  l  ?w2  
                      literalFalse l (elements M)  elementLevel (opposite l) M  elementLevel (opposite ?w1) M)"
                using 0  clause  clause < length (getF state)
                using ‹getWatch1 ?state' clause = Some ?w1[THEN sym]
                using ‹getWatch2 ?state' clause = Some ?w2[THEN sym]
                unfolding InvariantWatchCharacterization_def
                unfolding watchCharacterizationCondition_def
                unfolding swapWatches_def
                by simp
              with ¬ ( l. l el (nth (getF state) clause)  l  ?w1  l  ?w2  literalFalse l (elements M))
              have "l. l el (getF state ! clause)  literalTrue l (elements M)  elementLevel l M  elementLevel (opposite ?w1) M"
                by auto
              thus ?thesis
                unfolding setWatch2_def
                unfolding swapWatches_def
                by simp
            qed
          qed
          
          have "watchCharacterizationCondition l' ?w1 (getM ?fState) (getF ?fState ! clause)"
            using ¬ literalFalse l' (elements (getM ?state'))
            using ‹getM ?fState = getM state 
            unfolding swapWatches_def
            unfolding watchCharacterizationCondition_def
            by simp
          moreover
          have "watchCharacterizationCondition ?w1 l' (getM ?fState) (getF ?fState ! clause)"
          proof (cases "literalFalse ?w1 (elements (getM ?fState))")
            case True
            hence "literalFalse ?w1 (elements M)"
              using notifyWatchesLoopPreservedVariables[of "?state''" "Wl'" "literal" "newWl"]
              using ‹InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') ‹getF ?state'' = getF state
              using Cons(7) Cons(8)
              using ?w1  ?w2 ?w2 = literal
              unfolding setWatch2_def
              unfolding swapWatches_def
              by (simp add: Let_def)
            with ‹literalFalse ?w1 (elements M)  
              ( l. l el (nth (getF ?state'') clause)  literalTrue l (elements M)   elementLevel l M  elementLevel (opposite ?w1) M)
            obtain l::Literal
              where "l el (nth (getF ?state'') clause)" and 
              "literalTrue l (elements M)" and 
              "elementLevel l M  elementLevel (opposite ?w1) M"
              by auto
            hence "elementLevel l (getM state)  elementLevel (opposite ?w1) (getM state)"
              using Cons(8)
              using ‹literalTrue l (elements M) ‹literalFalse ?w1 (elements M)
              using elementLevelAppend[of "l" "M" "[(opposite literal, decision)]"]
              using elementLevelAppend[of "opposite ?w1" "M" "[(opposite literal, decision)]"]
              by auto
            thus ?thesis
              using l el (nth (getF ?state'') clause) ‹literalTrue l (elements M)
              using ‹getM ?fState = getM state ‹getF ?fState = getF state ‹getM ?state'' = getM state ‹getF ?state'' = getF state
              using Cons(8)
              unfolding watchCharacterizationCondition_def
              by auto
          next
            case False
            thus ?thesis
              unfolding watchCharacterizationCondition_def
              by simp
          qed
          ultimately
          show ?thesis
            by simp
        qed
        ultimately
        show ?thesis
          using Cons(1)[of "?state''" "newWl"]
          using Cons(7) Cons(8)
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ‹Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using ‹getWatch1 ?state'' clause = Some ?w1
          using ‹getWatch2 ?state'' clause = Some l'
          using Some
          using ‹uniq Wl'
          by (simp add: Let_def)
      next
        case None
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          let ?fState = "notifyWatches_loop literal Wl' (clause # newWl) ?state''"

          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            by auto
          moreover
          from Cons(3)
          have "InvariantWatchesDiffer (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
            unfolding InvariantWatchesDiffer_def
            unfolding swapWatches_def
            by auto
          moreover
          from Cons(4)
          have "InvariantConsistent (getM ?state')"
            unfolding InvariantConsistent_def
            unfolding swapWatches_def
            by simp
          moreover
          from Cons(5)
          have "InvariantUniq (getM ?state')"
            unfolding InvariantUniq_def
            unfolding swapWatches_def
            by simp
          moreover
          from Cons(6)
          have "InvariantWatchCharacterization (getF ?state') (getWatch1 ?state') (getWatch2 ?state') M"
            unfolding swapWatches_def
            unfolding InvariantWatchCharacterization_def
            unfolding watchCharacterizationCondition_def
            by simp
          moreover
          have "  (c::nat). c  set Wl'  Some literal = (getWatch1 ?state'' c)   Some literal = (getWatch2 ?state'' c)"
            using Cons(10)
            using clause  set Wl'
            using swapWatchesEffect[of "clause" "state"]
            by simp
          moreover
          have "getM ?state'' = getM state"
            "getF ?state'' = getF state"
            unfolding swapWatches_def
            by auto
          moreover
          have "getWatch1 ?fState clause = getWatch1 ?state'' clause  getWatch2 ?fState clause = getWatch2 ?state'' clause"
            using clause  set Wl'
            using ‹InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') ‹getF ?state'' = getF state
            using Cons(7)
            using notifyWatchesLoopPreservedWatches[of "?state''" "Wl'" "literal" "clause # newWl" ]
            by (simp add: Let_def)
          moreover
          have "literalFalse ?w1 (elements M)"
            using ‹literalFalse ?w1 (elements (getM ?state'))
              ?w1  ?w2 ?w2 = literal Cons(8)
            unfolding swapWatches_def
            by auto

          have "¬ literalTrue ?w2 (elements M)"
            using Cons(4)
            using Cons(8)
            using ?w2 = literal
            using inconsistentCharacterization[of "elements M @ [opposite literal]"]
            unfolding InvariantConsistent_def
            by force

          have *: " l. l el (nth (getF state) clause)  l  ?w1  l  ?w2  
            literalFalse l (elements M)  elementLevel (opposite l) M  elementLevel (opposite ?w1) M"
          proof-
            have "¬ ( l. l el (nth (getF state) clause)  literalTrue l (elements M))"
            proof
              assume " l. l el (nth (getF state) clause)  literalTrue l (elements M)"
              show "False"
              proof-
                from  l. l el (nth (getF state) clause)  literalTrue l (elements M)
                obtain l 
                  where "l el (nth (getF state) clause)" "literalTrue l (elements M)"
                  by auto
                hence "l  ?w1" "l  ?w2"
                  using ¬ literalTrue ?w1 (elements (getM ?state'))
                  using ¬ literalTrue ?w2 (elements M)
                  unfolding swapWatches_def
                  using Cons(8)
                  by auto
                with l el (nth (getF state) clause)
                have "literalFalse l (elements (getM ?state'))"
                  using ‹getWatch1 ?state' clause = Some ?w1
                  using ‹getWatch2 ?state' clause = Some ?w2
                  using None
                  using getNonWatchedUnfalsifiedLiteralNoneCharacterization[of "nth (getF ?state') clause" "?w1" "?w2" "getM ?state'"]
                  unfolding swapWatches_def
                  by simp
                with l  ?w2 ?w2 = literal Cons(8)
                have "literalFalse l (elements M)"
                  unfolding swapWatches_def
                  by simp
                with Cons(4) ‹literalTrue l (elements M)
                show ?thesis
                  unfolding InvariantConsistent_def
                  using Cons(8)
                  by (auto simp add: inconsistentCharacterization)
              qed
            qed
            with ‹InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) M
            show ?thesis
              unfolding InvariantWatchCharacterization_def
              using ‹literalFalse ?w1 (elements M)
              using ‹getWatch1 ?state' clause = Some ?w1[THEN sym]
              using ‹getWatch2 ?state' clause = Some ?w2[THEN sym]
              using 0  clause  clause < length (getF state)
              unfolding watchCharacterizationCondition_def
              unfolding swapWatches_def
              by (simp) (blast)
          qed
          
          have **: " l. l el (nth (getF ?state'') clause)  l  ?w1  l  ?w2  
                      literalFalse l (elements (getM ?state''))  
                      elementLevel (opposite l) (getM ?state'')  elementLevel (opposite ?w1) (getM ?state'')"
          proof-
            {

              fix l::Literal
              assume "l el (nth (getF ?state'') clause)  l  ?w1  l  ?w2"


              have "literalFalse l (elements (getM ?state''))  
                    elementLevel (opposite l) (getM ?state'')  elementLevel (opposite ?w1) (getM ?state'')"
              proof-
                from * l el (nth (getF ?state'') clause)  l  ?w1  l  ?w2
                have "literalFalse l (elements M)" "elementLevel (opposite l) M  elementLevel (opposite ?w1) M"
                  unfolding swapWatches_def
                  by auto
                thus ?thesis
                  using elementLevelAppend[of "opposite l" "M" "[(opposite literal, decision)]"]
                  using ‹literalFalse ?w1 (elements M)
                  using elementLevelAppend[of "opposite ?w1" "M" "[(opposite literal, decision)]"]
                  using Cons(8)
                  unfolding swapWatches_def
                  by simp
              qed
            }
            thus ?thesis
              by simp
          qed

          have "(getM ?fState) = (getM state)" "(getF ?fState) = (getF state)"
            using notifyWatchesLoopPreservedVariables[of "?state''" "Wl'" "literal" "clause # newWl"]
            using ‹InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') ‹getF ?state'' = getF state
            using Cons(7)
            unfolding swapWatches_def
            by (auto simp add: Let_def)
          hence " l. l el (nth (getF ?fState) clause)  l  ?w1  l  ?w2  
                      literalFalse l (elements (getM ?fState))  
                      elementLevel (opposite l) (getM ?fState)  elementLevel (opposite ?w1) (getM ?fState)"
            using **
            using ‹getM ?state'' = getM state
            using ‹getF ?state'' = getF state
            by simp
          moreover
          have " l. literalFalse l (elements (getM ?fState))  
                     elementLevel (opposite l) (getM ?fState)  elementLevel (opposite ?w2) (getM ?fState)"
          proof-
            have "elementLevel (opposite ?w2) (getM ?fState) = currentLevel (getM ?fState)"
              using Cons(8)
              using (getM ?fState) = (getM state)
              using ¬ literalFalse ?w2 (elements M)
              using ?w2 = literal
              using elementOnCurrentLevel[of "opposite ?w2" "M" "decision"]
              by simp
            thus ?thesis
              by (simp add: elementLevelLeqCurrentLevel)
          qed
          ultimately
          show ?thesis
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(7) Cons(8)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            using ‹uniq Wl'
            unfolding watchCharacterizationCondition_def
            by (simp add: Let_def)
        next
          case False

          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"
          let ?fState = "notifyWatches_loop literal Wl' (clause # newWl) ?state''"

          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding setReason_def
            unfolding swapWatches_def
            by auto
          moreover
          from Cons(3)
          have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesDiffer_def
            unfolding setReason_def
            unfolding swapWatches_def
            by auto
          moreover
          from Cons(4)
          have "InvariantConsistent (getM ?state'')"
            unfolding InvariantConsistent_def
            unfolding setReason_def
            unfolding swapWatches_def
            by simp
          moreover
          from Cons(5)
          have "InvariantUniq (getM ?state'')"
            unfolding InvariantUniq_def
            unfolding setReason_def
            unfolding swapWatches_def
            by simp
          moreover
          from Cons(6)
          have "InvariantWatchCharacterization (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') M"
            unfolding swapWatches_def
            unfolding setReason_def
            unfolding InvariantWatchCharacterization_def
            unfolding watchCharacterizationCondition_def
            by simp
          moreover
          have "  (c::nat). c  set Wl'  Some literal = (getWatch1 ?state'' c)   Some literal = (getWatch2 ?state'' c)"
            using Cons(10)
            using clause  set Wl'
            using swapWatchesEffect[of "clause" "state"]
            unfolding setReason_def
            by simp
          moreover
          have "getM ?state'' = getM state"
            "getF ?state'' = getF state"
            unfolding setReason_def
            unfolding swapWatches_def
            by auto
          moreover
          have "getWatch1 ?state'' clause = Some ?w1" "getWatch2 ?state'' clause = Some ?w2"
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            unfolding setReason_def
            unfolding swapWatches_def
            by auto
          moreover
          have "getWatch1 ?fState clause = Some ?w1" "getWatch2 ?fState clause = Some ?w2"
            using ‹getWatch1 ?state'' clause = Some ?w1 ‹getWatch2 ?state'' clause = Some ?w2
            using clause  set Wl'
            using ‹InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') ‹getF ?state'' = getF state
            using Cons(7)
            using notifyWatchesLoopPreservedWatches[of "?state''" "Wl'" "literal" "clause # newWl" ]
            by (auto simp add: Let_def)
          moreover
          have "(getM ?fState) = (getM state)" "(getF ?fState) = (getF state)"
            using notifyWatchesLoopPreservedVariables[of "?state''" "Wl'" "literal" "clause # newWl"]
            using ‹InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') ‹getF ?state'' = getF state
            using Cons(7)
            unfolding setReason_def
            unfolding swapWatches_def
            by (auto simp add: Let_def)
          ultimately 
          have "c. c  set Wl'  (w1 w2. Some w1 = getWatch1 ?fState c  Some w2 = getWatch2 ?fState c 
               watchCharacterizationCondition w1 w2 (getM ?fState) (getF ?fState ! c) 
               watchCharacterizationCondition w2 w1 (getM ?fState) (getF ?fState ! c))" and
               "?fState = notifyWatches_loop literal (clause # Wl') newWl state"
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(7) Cons(8)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            using ‹uniq Wl'
            by (auto simp add: Let_def)
          moreover
          have *: " l. l el (nth (getF ?state'') clause)  l  ?w1  l  ?w2  literalFalse l (elements (getM ?state''))"
            using None
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using getNonWatchedUnfalsifiedLiteralNoneCharacterization[of "nth (getF ?state') clause" "?w1" "?w2" "getM ?state'"]
            using Cons(8)
            unfolding setReason_def
            unfolding swapWatches_def
            by auto

          have**: " l. l el (nth (getF ?fState) clause)  l  ?w1  l  ?w2  literalFalse l (elements (getM ?fState))"
            using (getM ?fState) = (getM state) (getF ?fState) = (getF state)
            using *
            using ‹getM ?state'' = getM state
            using ‹getF ?state'' = getF state
            unfolding swapWatches_def
            by auto

          have ***: " l. literalFalse l (elements (getM ?fState))  
                     elementLevel (opposite l) (getM ?fState)  elementLevel (opposite ?w2) (getM ?fState)"
          proof-
            have "elementLevel (opposite ?w2) (getM ?fState) = currentLevel (getM ?fState)"
              using Cons(8)
              using (getM ?fState) = (getM state)
              using ¬ literalFalse ?w2 (elements M)
              using ?w2 = literal
              using elementOnCurrentLevel[of "opposite ?w2" "M" "decision"]
              by simp
            thus ?thesis
              by (simp add: elementLevelLeqCurrentLevel)
          qed

          have "(w1 w2. Some w1 = getWatch1 ?fState clause  Some w2 = getWatch2 ?fState clause 
            watchCharacterizationCondition w1 w2 (getM ?fState) (getF ?fState ! clause) 
            watchCharacterizationCondition w2 w1 (getM ?fState) (getF ?fState ! clause))"
          proof-
            {
              fix w1 w2
              assume "Some w1 = getWatch1 ?fState clause  Some w2 = getWatch2 ?fState clause"
              hence "w1 = ?w1" "w2 = ?w2"
                using ‹getWatch1 ?fState clause = Some ?w1
                using ‹getWatch2 ?fState clause = Some ?w2
                by auto
              hence "watchCharacterizationCondition w1 w2 (getM ?fState) (getF ?fState ! clause) 
                watchCharacterizationCondition w2 w1 (getM ?fState) (getF ?fState ! clause)"
                unfolding watchCharacterizationCondition_def
                using ** ***
                unfolding watchCharacterizationCondition_def
                using (getM ?fState) = (getM state) (getF ?fState) = (getF state)
                using ¬ literalFalse ?w1 (elements (getM ?state'))
                unfolding swapWatches_def
                by simp
            }
            thus ?thesis
              by auto
          qed
          ultimately
          show ?thesis
            by simp
        qed
      qed
    qed
  next
    case False
    let ?state' = state
    let ?w1 = wa
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch1 state clause = Some wa
      by auto
    let ?w2 = wb
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch2 state clause = Some wb
      by auto
    
    from ¬ Some literal = getWatch1 state clause
       (c::nat). c  set (clause # Wl')  Some literal = (getWatch1 state c)   Some literal = (getWatch2 state c)
    have "Some literal = getWatch2 state clause"
      by auto
    hence "?w2 = literal"
      using ‹getWatch2 ?state' clause = Some ?w2
      by simp
    hence "literalFalse ?w2 (elements (getM state))"
      using Cons(8)
      by simp

    from ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)
    have "?w1 el (nth (getF state) clause)" "?w2 el (nth (getF state) clause)"
      using ‹getWatch1 ?state' clause = Some ?w1
      using ‹getWatch2 ?state' clause = Some ?w2
      using 0  clause  clause < length (getF state)
      unfolding InvariantWatchesEl_def
      by auto

    from ‹InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)
    have "?w1  ?w2"
      using ‹getWatch1 ?state' clause = Some ?w1
      using ‹getWatch2 ?state' clause = Some ?w2
      using 0  clause  clause < length (getF state)
      unfolding InvariantWatchesDiffer_def
      by auto

    have "¬ literalFalse ?w2 (elements M)"
      using ?w2 = literal
      using Cons(5)
      using Cons(8)
      unfolding InvariantUniq_def
      by (simp add: uniqAppendIff)

    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True

      let ?fState = "notifyWatches_loop literal Wl' (clause # newWl) ?state'"

      have "getWatch1 ?fState clause = getWatch1 ?state' clause  getWatch2 ?fState clause = getWatch2 ?state' clause"
        using clause  set Wl'
        using Cons(2) 
        using Cons(7)
        using notifyWatchesLoopPreservedWatches[of "?state'" "Wl'" "literal" "clause # newWl" ]
        by (simp add: Let_def)
      moreover
      have "watchCharacterizationCondition ?w1 ?w2 (getM ?fState) (getF ?fState ! clause) 
            watchCharacterizationCondition ?w2 ?w1 (getM ?fState) (getF ?fState ! clause)"
      proof-
        have "(getM ?fState) = (getM state)  (getF ?fState = getF state)"
          using notifyWatchesLoopPreservedVariables[of "?state'" "Wl'" "literal" "clause # newWl"]
          using Cons(2)
          using Cons(7)
          by (simp add: Let_def)
        moreover
        have "¬ literalFalse ?w1 (elements M)"
          using ‹literalTrue ?w1 (elements (getM ?state')) ?w1  ?w2 ?w2 = literal
          using Cons(4) Cons(8)
          unfolding InvariantConsistent_def
          by (auto simp add: inconsistentCharacterization)
        moreover 
        have "elementLevel (opposite ?w2) (getM ?state') = currentLevel (getM ?state')"
          using ?w2 = literal
          using Cons(5) Cons(8)
          unfolding InvariantUniq_def
          by (auto simp add: uniqAppendIff elementOnCurrentLevel)
        ultimately
        show ?thesis
          using ‹getWatch1 ?fState clause = getWatch1 ?state' clause  getWatch2 ?fState clause = getWatch2 ?state' clause
          using ?w2 = literal ?w1  ?w2
          using ?w1 el (nth (getF state) clause)
          using ‹literalTrue ?w1 (elements (getM ?state'))
          unfolding watchCharacterizationCondition_def
          using elementLevelLeqCurrentLevel[of "?w1" "getM ?state'"]
          using notifyWatchesLoopPreservedVariables[of "?state'" "Wl'" "literal" "clause # newWl"]
          using ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state) 
          using Cons(7) 
          using Cons(8)
          by (auto simp add: Let_def)
      qed
      ultimately
      show ?thesis
        using assms
        using Cons(1)[of "?state'" "clause # newWl"]
        using Cons(2) Cons(3) Cons(4) Cons(5) Cons(6) Cons(7) Cons(8) Cons(9) Cons(10)
        using ‹uniq Wl'
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹Some literal = getWatch2 state clause
        using ‹literalTrue ?w1 (elements (getM ?state'))
        using ?w1  ?w2
        by (simp add:Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state') clause)" "l'  ?w1" "l'  ?w2" "¬ literalFalse l' (elements (getM ?state'))"
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by auto

        let ?state'' = "setWatch2 clause l' ?state'"
        let ?fState = "notifyWatches_loop literal Wl' newWl ?state''"

        from Cons(2)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state') clause)
          unfolding InvariantWatchesEl_def
          unfolding setWatch2_def
          by auto
        moreover
        from Cons(3)
        have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l'  ?w1
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          unfolding InvariantWatchesDiffer_def
          unfolding setWatch2_def
          by auto
        moreover
        from Cons(4)
        have "InvariantConsistent (getM ?state'')"
          unfolding InvariantConsistent_def
          unfolding setWatch2_def
          by simp
        moreover
        from Cons(5)
        have "InvariantUniq (getM ?state'')"
          unfolding InvariantUniq_def
          unfolding setWatch2_def
          by simp
        moreover
        have "InvariantWatchCharacterization (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') M"
        proof-
          {
            fix c::nat and ww1::Literal and ww2::Literal
            assume a: "0  c  c < length (getF ?state'')  Some ww1 = (getWatch1 ?state'' c)  Some ww2 = (getWatch2 ?state'' c)"
            assume b: "literalFalse ww1 (elements M)"
              
            have "(l. l el ((getF ?state'') ! c)  literalTrue l (elements M)  elementLevel l M  elementLevel (opposite ww1) M) 
                  (l. l el ((getF ?state'') ! c)  l  ww1  l  ww2  
                        literalFalse l (elements M)  elementLevel (opposite l) M  elementLevel (opposite ww1) M)"
            proof (cases "c = clause")
              case False
              thus ?thesis
                using a and b
                using Cons(6)
                unfolding InvariantWatchCharacterization_def
                unfolding watchCharacterizationCondition_def
                unfolding setWatch2_def
                by simp
            next
              case True
              with a 
              have "ww1 = ?w1" and "ww2 = l'"
                using ‹getWatch1 ?state' clause = Some ?w1
                using ‹getWatch2 ?state' clause = Some ?w2[THEN sym]
                unfolding setWatch2_def
                by auto
              
              have "¬ (l. l el (getF state ! clause)  l  ?w1  l  ?w2  literalFalse l (elements M))"
                using Cons(8)
                using l'  ?w1 and l'  ?w2 l' el (nth (getF ?state') clause)
                using ¬ literalFalse l' (elements (getM ?state'))
                using a and b
                using c = clause
                unfolding setWatch2_def
                by auto
              moreover
              have "(l. l el (getF state ! clause)  literalTrue l (elements M)  
                elementLevel l M  elementLevel (opposite ?w1) M) 
                (l. l el (getF state ! clause)  l  ?w1  l  ?w2  literalFalse l (elements M))"
                using Cons(6)
                unfolding InvariantWatchCharacterization_def
                unfolding watchCharacterizationCondition_def
                using 0  clause  clause < length (getF state)
                using ‹getWatch1 ?state' clause = Some ?w1[THEN sym]
                using ‹getWatch2 ?state' clause = Some ?w2[THEN sym]
                using ‹literalFalse ww1 (elements M)
                using ww1 = ?w1
                unfolding setWatch2_def
                by auto
              ultimately
              show ?thesis
                using ww1 = ?w1
                using c = clause
                unfolding setWatch2_def
                by auto
            qed
          }
          moreover 
          {
            fix c::nat and ww1::Literal and ww2::Literal
            assume a: "0  c  c < length (getF ?state'')  Some ww1 = (getWatch1 ?state'' c)  Some ww2 = (getWatch2 ?state'' c)"
            assume b: "literalFalse ww2 (elements M)"
            
            have "(l. l el ((getF ?state'') ! c)  literalTrue l (elements M)  elementLevel l M  elementLevel (opposite ww2) M) 
                  (l. l el ((getF ?state'') ! c)  l  ww1  l  ww2  
                       literalFalse l (elements M)  elementLevel (opposite l) M  elementLevel (opposite ww2) M)"
            proof (cases "c = clause")
              case False
              thus ?thesis
                using a and b
                using Cons(6)
                unfolding InvariantWatchCharacterization_def
                unfolding watchCharacterizationCondition_def
                unfolding setWatch2_def
                by auto
            next
              case True
              with a 
              have "ww1 = ?w1" and "ww2 = l'"
                using ‹getWatch1 ?state' clause = Some ?w1
                using ‹getWatch2 ?state' clause = Some ?w2[THEN sym]
                unfolding setWatch2_def
                by auto
              with ¬ literalFalse l' (elements (getM ?state')) b
                Cons(8)
              have False
                by simp
              thus ?thesis
                by simp
            qed
          }
          ultimately
          show ?thesis
            unfolding InvariantWatchCharacterization_def
            unfolding watchCharacterizationCondition_def
            by blast
        qed
        moreover
        have "  (c::nat). c  set Wl'  Some literal = (getWatch1 ?state'' c)   Some literal = (getWatch2 ?state'' c)"
          using Cons(10)
          using clause  set Wl'
          unfolding setWatch2_def
          by simp
        moreover
        have "getM ?state'' = getM state"
          "getF ?state'' = getF state"
          unfolding setWatch2_def
          by auto
        moreover
        have "getWatch1 ?state'' clause = Some ?w1" "getWatch2 ?state'' clause = Some l'"
          using ‹getWatch1 ?state' clause = Some ?w1
          unfolding setWatch2_def
          by auto
        hence "getWatch1 ?fState clause = getWatch1 ?state'' clause  getWatch2 ?fState clause = Some l'"
          using clause  set Wl'
          using ‹InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') ‹getF ?state'' = getF state
          using Cons(7)
          using notifyWatchesLoopPreservedWatches[of "?state''" "Wl'" "literal" "newWl"]
          by (simp add: Let_def)
        moreover
        have "watchCharacterizationCondition ?w1 l' (getM ?fState) (getF ?fState ! clause) 
          watchCharacterizationCondition l' ?w1 (getM ?fState) (getF ?fState ! clause)"
        proof-
          have "(getM ?fState) = (getM state)" "(getF ?fState) = (getF state)"
            using notifyWatchesLoopPreservedVariables[of "?state''" "Wl'" "literal" "newWl"]
            using ‹InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') ‹getF ?state'' = getF state
            using Cons(7)
            unfolding setWatch2_def
            by (auto simp add: Let_def)
          
          have "literalFalse ?w1 (elements M)  
            ( l. l el (nth (getF ?state'') clause)  literalTrue l (elements M)   elementLevel l M  elementLevel (opposite ?w1) M)"
          proof
            assume "literalFalse ?w1 (elements M)"
            show " l. l el (nth (getF ?state'') clause)  literalTrue l (elements M)   elementLevel l M  elementLevel (opposite ?w1) M"
            proof-
              have "¬ ( l. l el (nth (getF state) clause)  l  ?w1  l  ?w2  literalFalse l (elements M))"
                using l' el (nth (getF ?state') clause) l'  ?w1 l'  ?w2 ¬ literalFalse l' (elements (getM ?state'))
                using Cons(8)
                unfolding swapWatches_def
                by auto

              from ‹literalFalse ?w1 (elements M) Cons(6)
              have
                "(l. l el (getF state ! clause)  literalTrue l (elements M)  elementLevel l M  elementLevel (opposite ?w1) M) 
                 (l. l el (getF state ! clause)  l  ?w1  l  ?w2  
                      literalFalse l (elements M)  elementLevel (opposite l) M  elementLevel (opposite ?w1) M)"
                using 0  clause  clause < length (getF state)
                using ‹getWatch1 ?state' clause = Some ?w1[THEN sym]
                using ‹getWatch2 ?state' clause = Some ?w2[THEN sym]
                unfolding InvariantWatchCharacterization_def
                unfolding watchCharacterizationCondition_def
                by simp
              with ¬ ( l. l el (nth (getF state) clause)  l  ?w1  l  ?w2  literalFalse l (elements M))
              have "l. l el (getF state ! clause)  literalTrue l (elements M)  elementLevel l M  elementLevel (opposite ?w1) M"
                by auto
              thus ?thesis
                unfolding setWatch2_def
                by simp
            qed
          qed
          moreover
          have "watchCharacterizationCondition l' ?w1 (getM ?fState) (getF ?fState ! clause)"
            using ¬ literalFalse l' (elements (getM ?state'))
            using ‹getM ?fState = getM state 
            unfolding watchCharacterizationCondition_def
            by simp
          moreover
          have "watchCharacterizationCondition ?w1 l' (getM ?fState) (getF ?fState ! clause)"
          proof (cases "literalFalse ?w1 (elements (getM ?fState))")
            case True
            hence "literalFalse ?w1 (elements M)"
              using notifyWatchesLoopPreservedVariables[of "?state''" "Wl'" "literal" "newWl"]
              using ‹InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') ‹getF ?state'' = getF state
              using Cons(7) Cons(8)
              using ?w1  ?w2 ?w2 = literal
              unfolding setWatch2_def
              by (simp add: Let_def)
            with ‹literalFalse ?w1 (elements M)  
              ( l. l el (nth (getF ?state'') clause)  literalTrue l (elements M)   elementLevel l M  elementLevel (opposite ?w1) M)
            obtain l::Literal
              where "l el (nth (getF ?state'') clause)" and 
              "literalTrue l (elements M)" and 
              "elementLevel l M  elementLevel (opposite ?w1) M"
              by auto
            hence "elementLevel l (getM state)  elementLevel (opposite ?w1) (getM state)"
              using Cons(8)
              using ‹literalTrue l (elements M) ‹literalFalse ?w1 (elements M)
              using elementLevelAppend[of "l" "M" "[(opposite literal, decision)]"]
              using elementLevelAppend[of "opposite ?w1" "M" "[(opposite literal, decision)]"]
              by auto
            thus ?thesis
              using l el (nth (getF ?state'') clause) ‹literalTrue l (elements M)
              using ‹getM ?fState = getM state ‹getF ?fState = getF state ‹getM ?state'' = getM state ‹getF ?state'' = getF state
              using Cons(8)
              unfolding watchCharacterizationCondition_def
              by auto
          next
            case False
            thus ?thesis
              unfolding watchCharacterizationCondition_def
              by simp
          qed
          ultimately
          show ?thesis
            by simp
        qed
        ultimately
        show ?thesis
          using Cons(1)[of "?state''" "newWl"]
          using Cons(7) Cons(8)
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ‹Some literal = getWatch2 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using ‹getWatch1 ?state'' clause = Some ?w1
          using ‹getWatch2 ?state'' clause = Some l'
          using Some
          using ‹uniq Wl'
          using ?w1  ?w2
          by (simp add: Let_def)
      next
        case None
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          let ?fState = "notifyWatches_loop literal Wl' (clause # newWl) ?state''"

          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            by auto
          moreover
          from Cons(3)
          have "InvariantWatchesDiffer (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
            unfolding InvariantWatchesDiffer_def
            by auto
          moreover
          from Cons(4)
          have "InvariantConsistent (getM ?state')"
            unfolding InvariantConsistent_def
            by simp
          moreover
          from Cons(5)
          have "InvariantUniq (getM ?state')"
            unfolding InvariantUniq_def
            by simp
          moreover
          from Cons(6)
          have "InvariantWatchCharacterization (getF ?state') (getWatch1 ?state') (getWatch2 ?state') M"
            unfolding InvariantWatchCharacterization_def
            unfolding watchCharacterizationCondition_def
            by simp
          moreover
          have "  (c::nat). c  set Wl'  Some literal = (getWatch1 ?state'' c)   Some literal = (getWatch2 ?state'' c)"
            using Cons(10)
            using clause  set Wl'
            by simp
          moreover
          have "getM ?state'' = getM state"
            "getF ?state'' = getF state"
            by auto
          moreover
          have "getWatch1 ?fState clause = getWatch1 ?state'' clause  getWatch2 ?fState clause = getWatch2 ?state'' clause"
            using clause  set Wl'
            using ‹InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') ‹getF ?state'' = getF state
            using Cons(7)
            using notifyWatchesLoopPreservedWatches[of "?state''" "Wl'" "literal" "clause # newWl" ]
            by (simp add: Let_def)
          moreover
          have "literalFalse ?w1 (elements M)"
            using ‹literalFalse ?w1 (elements (getM ?state'))
              ?w1  ?w2 ?w2 = literal Cons(8)
            by auto

          have "¬ literalTrue ?w2 (elements M)"
            using Cons(4)
            using Cons(8)
            using ?w2 = literal
            using inconsistentCharacterization[of "elements M @ [opposite literal]"]
            unfolding InvariantConsistent_def
            by force

          have *: " l. l el (nth (getF state) clause)  l  ?w1  l  ?w2  
            literalFalse l (elements M)  elementLevel (opposite l) M  elementLevel (opposite ?w1) M"
          proof-
            have "¬ ( l. l el (nth (getF state) clause)  literalTrue l (elements M))"
            proof
              assume " l. l el (nth (getF state) clause)  literalTrue l (elements M)"
              show "False"
              proof-
                from  l. l el (nth (getF state) clause)  literalTrue l (elements M)
                obtain l 
                  where "l el (nth (getF state) clause)" "literalTrue l (elements M)"
                  by auto
                hence "l  ?w1" "l  ?w2"
                  using ¬ literalTrue ?w1 (elements (getM ?state'))
                  using ¬ literalTrue ?w2 (elements M)
                  using Cons(8)
                  by auto
                with l el (nth (getF state) clause)
                have "literalFalse l (elements (getM ?state'))"
                  using ‹getWatch1 ?state' clause = Some ?w1
                  using ‹getWatch2 ?state' clause = Some ?w2
                  using None
                  using getNonWatchedUnfalsifiedLiteralNoneCharacterization[of "nth (getF ?state') clause" "?w1" "?w2" "getM ?state'"]
                  by simp
                with l  ?w2 ?w2 = literal Cons(8)
                have "literalFalse l (elements M)"
                  by simp
                with Cons(4) ‹literalTrue l (elements M)
                show ?thesis
                  unfolding InvariantConsistent_def
                  using Cons(8)
                  by (auto simp add: inconsistentCharacterization)
              qed
            qed
            with ‹InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) M
            show ?thesis
              unfolding InvariantWatchCharacterization_def
              using ‹literalFalse ?w1 (elements M)
              using ‹getWatch1 ?state' clause = Some ?w1[THEN sym]
              using ‹getWatch2 ?state' clause = Some ?w2[THEN sym]
              using 0  clause  clause < length (getF state)
              unfolding watchCharacterizationCondition_def
              by (simp) (blast)
          qed
          
          have **: " l. l el (nth (getF ?state'') clause)  l  ?w1  l  ?w2  
                      literalFalse l (elements (getM ?state''))  
                      elementLevel (opposite l) (getM ?state'')  elementLevel (opposite ?w1) (getM ?state'')"
          proof-
            {

              fix l::Literal
              assume "l el (nth (getF ?state'') clause)  l  ?w1  l  ?w2"


              have "literalFalse l (elements (getM ?state''))  
                    elementLevel (opposite l) (getM ?state'')  elementLevel (opposite ?w1) (getM ?state'')"
              proof-
                from * l el (nth (getF ?state'') clause)  l  ?w1  l  ?w2
                have "literalFalse l (elements M)" "elementLevel (opposite l) M  elementLevel (opposite ?w1) M"
                  by auto
                thus ?thesis
                  using elementLevelAppend[of "opposite l" "M" "[(opposite literal, decision)]"]
                  using ‹literalFalse ?w1 (elements M)
                  using elementLevelAppend[of "opposite ?w1" "M" "[(opposite literal, decision)]"]
                  using Cons(8)
                  by simp
              qed
            }
            thus ?thesis
              by simp
          qed

          have "(getM ?fState) = (getM state)" "(getF ?fState) = (getF state)"
            using notifyWatchesLoopPreservedVariables[of "?state''" "Wl'" "literal" "clause # newWl"]
            using ‹InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') ‹getF ?state'' = getF state
            using Cons(7)
            by (auto simp add: Let_def)
          hence " l. l el (nth (getF ?fState) clause)  l  ?w1  l  ?w2  
                      literalFalse l (elements (getM ?fState))  
                      elementLevel (opposite l) (getM ?fState)  elementLevel (opposite ?w1) (getM ?fState)"
            using **
            using ‹getM ?state'' = getM state
            using ‹getF ?state'' = getF state
            by simp
          moreover
          have " l. literalFalse l (elements (getM ?fState))  
                     elementLevel (opposite l) (getM ?fState)  elementLevel (opposite ?w2) (getM ?fState)"
          proof-
            have "elementLevel (opposite ?w2) (getM ?fState) = currentLevel (getM ?fState)"
              using Cons(8)
              using (getM ?fState) = (getM state)
              using ¬ literalFalse ?w2 (elements M)
              using ?w2 = literal
              using elementOnCurrentLevel[of "opposite ?w2" "M" "decision"]
              by simp
            thus ?thesis
              by (simp add: elementLevelLeqCurrentLevel)
          qed
          ultimately
          show ?thesis
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(7) Cons(8)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch2 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            using ‹uniq Wl'
            using ?w1  ?w2
            unfolding watchCharacterizationCondition_def
            by (simp add: Let_def)
        next
          case False

          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"
          let ?fState = "notifyWatches_loop literal Wl' (clause # newWl) ?state''"

          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding setReason_def
            by auto
          moreover
          from Cons(3)
          have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesDiffer_def
            unfolding setReason_def
            by auto
          moreover
          from Cons(4)
          have "InvariantConsistent (getM ?state'')"
            unfolding InvariantConsistent_def
            unfolding setReason_def
            by simp
          moreover
          from Cons(5)
          have "InvariantUniq (getM ?state'')"
            unfolding InvariantUniq_def
            unfolding setReason_def
            by simp
          moreover
          from Cons(6)
          have "InvariantWatchCharacterization (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') M"
            unfolding setReason_def
            unfolding InvariantWatchCharacterization_def
            unfolding watchCharacterizationCondition_def
            by simp
          moreover
          have "  (c::nat). c  set Wl'  Some literal = (getWatch1 ?state'' c)   Some literal = (getWatch2 ?state'' c)"
            using Cons(10)
            using clause  set Wl'
            unfolding setReason_def
            by simp
          moreover
          have "getM ?state'' = getM state"
            "getF ?state'' = getF state"
            unfolding setReason_def
            by auto
          moreover
          have "getWatch1 ?state'' clause = Some ?w1" "getWatch2 ?state'' clause = Some ?w2"
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            unfolding setReason_def
            by auto
          moreover
          have "getWatch1 ?fState clause = Some ?w1" "getWatch2 ?fState clause = Some ?w2"
            using ‹getWatch1 ?state'' clause = Some ?w1 ‹getWatch2 ?state'' clause = Some ?w2
            using clause  set Wl'
            using ‹InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') ‹getF ?state'' = getF state
            using Cons(7)
            using notifyWatchesLoopPreservedWatches[of "?state''" "Wl'" "literal" "clause # newWl" ]
            by (auto simp add: Let_def)
          moreover
          have "(getM ?fState) = (getM state)" "(getF ?fState) = (getF state)"
            using notifyWatchesLoopPreservedVariables[of "?state''" "Wl'" "literal" "clause # newWl"]
            using ‹InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') ‹getF ?state'' = getF state
            using Cons(7)
            unfolding setReason_def
            by (auto simp add: Let_def)
          ultimately 
          have "c. c  set Wl'  (w1 w2. Some w1 = getWatch1 ?fState c  Some w2 = getWatch2 ?fState c 
               watchCharacterizationCondition w1 w2 (getM ?fState) (getF ?fState ! c) 
               watchCharacterizationCondition w2 w1 (getM ?fState) (getF ?fState ! c))" and
               "?fState = notifyWatches_loop literal (clause # Wl') newWl state"
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(7) Cons(8)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch2 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            using ‹uniq Wl'
            by (auto simp add: Let_def)
          moreover
          have *: " l. l el (nth (getF ?state'') clause)  l  ?w1  l  ?w2  literalFalse l (elements (getM ?state''))"
            using None
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using getNonWatchedUnfalsifiedLiteralNoneCharacterization[of "nth (getF ?state') clause" "?w1" "?w2" "getM ?state'"]
            using Cons(8)
            unfolding setReason_def
            by auto

          have**: " l. l el (nth (getF ?fState) clause)  l  ?w1  l  ?w2  literalFalse l (elements (getM ?fState))"
            using (getM ?fState) = (getM state) (getF ?fState) = (getF state)
            using *
            using ‹getM ?state'' = getM state
            using ‹getF ?state'' = getF state
            by auto

          have ***: " l. literalFalse l (elements (getM ?fState))  
                     elementLevel (opposite l) (getM ?fState)  elementLevel (opposite ?w2) (getM ?fState)"
          proof-
            have "elementLevel (opposite ?w2) (getM ?fState) = currentLevel (getM ?fState)"
              using Cons(8)
              using (getM ?fState) = (getM state)
              using ¬ literalFalse ?w2 (elements M)
              using ?w2 = literal
              using elementOnCurrentLevel[of "opposite ?w2" "M" "decision"]
              by simp
            thus ?thesis
              by (simp add: elementLevelLeqCurrentLevel)
          qed

          have "(w1 w2. Some w1 = getWatch1 ?fState clause  Some w2 = getWatch2 ?fState clause 
            watchCharacterizationCondition w1 w2 (getM ?fState) (getF ?fState ! clause) 
            watchCharacterizationCondition w2 w1 (getM ?fState) (getF ?fState ! clause))"
          proof-
            {
              fix w1 w2
              assume "Some w1 = getWatch1 ?fState clause  Some w2 = getWatch2 ?fState clause"
              hence "w1 = ?w1" "w2 = ?w2"
                using ‹getWatch1 ?fState clause = Some ?w1
                using ‹getWatch2 ?fState clause = Some ?w2
                by auto
              hence "watchCharacterizationCondition w1 w2 (getM ?fState) (getF ?fState ! clause) 
                watchCharacterizationCondition w2 w1 (getM ?fState) (getF ?fState ! clause)"
                unfolding watchCharacterizationCondition_def
                using ** ***
                unfolding watchCharacterizationCondition_def
                using (getM ?fState) = (getM state) (getF ?fState) = (getF state)
                using ¬ literalFalse ?w1 (elements (getM ?state'))
                by simp
            }
            thus ?thesis
              by auto
          qed
          ultimately
          show ?thesis
            by simp
        qed
      qed
    qed
  qed
qed
  

lemma NotifyWatchesLoopConflictFlagEffect:
fixes literal :: Literal and Wl :: "nat list" and newWl :: "nat list" and state :: State
assumes 
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  " (c::nat). c  set Wl  0  c  c < length (getF state)" and
  "InvariantConsistent (getM state)"
  " (c::nat). c  set Wl  Some literal = (getWatch1 state c)   Some literal = (getWatch2 state c)"
  "literalFalse literal (elements (getM state))"
  "uniq Wl"
shows
  "let state' = notifyWatches_loop literal Wl newWl state in
     getConflictFlag state' = 
        (getConflictFlag state  
         ( clause. clause  set Wl  clauseFalse (nth (getF state) clause) (elements (getM state))))"
using assms
proof (induct Wl arbitrary: newWl state)
  case Nil
  thus ?case
    by simp
next
  case (Cons clause Wl')
  
  from ‹uniq (clause # Wl')
  have "uniq Wl'" and "clause  set Wl'"
    by (auto simp add: uniqAppendIff)

  from  (c::nat). c  set (clause # Wl')  0  c  c < length (getF state)
  have "0  clause" "clause < length (getF state)"
    by auto
  then obtain wa::Literal and wb::Literal
    where "getWatch1 state clause = Some wa" and "getWatch2 state clause = Some wb"
    using Cons
    unfolding InvariantWatchesEl_def
    by auto
  show ?case
  proof (cases "Some literal = getWatch1 state clause")
    case True
    let ?state' = "swapWatches clause state"
    let ?w1 = wb
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch2 state clause = Some wb
      unfolding swapWatches_def
      by auto
    let ?w2 = wa
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch1 state clause = Some wa
      unfolding swapWatches_def
      by auto

    from ‹Some literal = getWatch1 state clause
      ‹getWatch2 ?state' clause = Some ?w2
    ‹literalFalse literal (elements (getM state))
    have "literalFalse ?w2 (elements (getM state))"
      unfolding swapWatches_def
      by simp

    from ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)
    have "?w1 el (nth (getF state) clause)"
      using ‹getWatch1 ?state' clause = Some ?w1
      using ‹getWatch2 ?state' clause = Some ?w2
      using clause < length (getF state)
      unfolding InvariantWatchesEl_def
      unfolding swapWatches_def
      by auto

    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True
      
      from Cons(2)
      have "InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
        unfolding InvariantWatchesEl_def
        unfolding swapWatches_def
        by auto
      moreover
      have "getF ?state' = getF state  
        getM ?state' = getM state  
        getConflictFlag ?state' = getConflictFlag state
        "
        unfolding swapWatches_def
        by simp
      moreover
      have "c. c  set Wl'  Some literal = getWatch1 ?state' c  Some literal = getWatch2 ?state' c"
        using Cons(5)
        unfolding swapWatches_def
        by auto
      moreover
      have "¬ clauseFalse (nth (getF state) clause) (elements (getM state))"
        using ?w1 el (nth (getF state) clause)
        using ‹literalTrue ?w1 (elements (getM ?state'))
        using ‹InvariantConsistent (getM state)
        unfolding InvariantConsistent_def
        unfolding swapWatches_def
          by (auto simp add: clauseFalseIffAllLiteralsAreFalse inconsistentCharacterization)
      ultimately
      show ?thesis
        using Cons(1)[of "?state'" "clause # newWl"]
        using Cons(3) Cons(4) Cons(6)
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹Some literal = getWatch1 state clause
        using ‹literalTrue ?w1 (elements (getM ?state'))
        using ‹uniq Wl'
        by (auto simp add:Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state') clause)" "¬ literalFalse l' (elements (getM ?state'))"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by auto

        let ?state'' = "setWatch2 clause l' ?state'"

        from Cons(2)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state') clause)
          unfolding InvariantWatchesEl_def
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        moreover
        from Cons(4)
        have "InvariantConsistent (getM ?state'')"
          unfolding setWatch2_def
          unfolding swapWatches_def
          by simp
        moreover
        have "getM ?state'' = getM state 
          getF ?state'' = getF state  
          getConflictFlag ?state'' = getConflictFlag state"
          unfolding swapWatches_def
          unfolding setWatch2_def
          by simp
        moreover
        have "c. c  set Wl'  Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c"
          using Cons(5)
          using clause  set Wl'
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        moreover
        have "¬ clauseFalse (nth (getF state) clause) (elements (getM state))"
          using l' el (nth (getF ?state') clause) 
          using ¬ literalFalse l' (elements (getM ?state'))
          using ‹InvariantConsistent (getM state)
          unfolding InvariantConsistent_def
          unfolding swapWatches_def
          by (auto simp add: clauseFalseIffAllLiteralsAreFalse inconsistentCharacterization)
        ultimately
        show ?thesis
          using Cons(1)[of "?state''" "newWl"]
          using Cons(3) Cons(4) Cons(6)
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ‹Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using ‹uniq Wl'
          using Some
          by (auto simp add: Let_def)
      next
        case None
        hence " l. l el (nth (getF ?state') clause)  l  ?w1  l  ?w2  literalFalse l (elements (getM ?state'))"
          using getNonWatchedUnfalsifiedLiteralNoneCharacterization
          by simp
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            by auto
          moreover
          from Cons(4)
          have "InvariantConsistent (getM ?state'')"
            unfolding setWatch2_def
            unfolding swapWatches_def
            by simp
          moreover
          have "getM ?state'' = getM state 
          getF ?state'' = getF state  
          getSATFlag ?state'' = getSATFlag state"
            unfolding swapWatches_def
            by simp
          moreover
          have "c. c  set Wl'  Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c"
            using Cons(5)
            using clause  set Wl'
            unfolding swapWatches_def
            unfolding setWatch2_def
            by auto
          moreover
          have "clauseFalse (nth (getF state) clause) (elements (getM state))"
            using  l. l el (nth (getF ?state') clause)  l  ?w1  l  ?w2  literalFalse l (elements (getM ?state'))
            using ‹literalFalse ?w1 (elements (getM ?state'))
            using ‹literalFalse ?w2 (elements (getM state))
            unfolding swapWatches_def
            by (auto simp add: clauseFalseIffAllLiteralsAreFalse)
          ultimately
          show ?thesis
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(3) Cons(4) Cons(6)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            using ‹uniq Wl'
            by (auto simp add: Let_def)
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"

          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          from Cons(4)
          have "InvariantConsistent (getM ?state'')"
            unfolding swapWatches_def
            unfolding setReason_def
            by simp
          moreover
          have "getM ?state'' = getM state 
            getF ?state'' = getF state  
            getSATFlag ?state'' = getSATFlag state"
            unfolding swapWatches_def
            unfolding setReason_def
            by simp
          moreover
          have "c. c  set Wl'  Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c"
            using Cons(5)
            using clause  set Wl'
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          have "¬ clauseFalse (nth (getF state) clause) (elements (getM state))"
            using ?w1 el (nth (getF state) clause)
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            using ‹InvariantConsistent (getM state)
            unfolding InvariantConsistent_def
          unfolding swapWatches_def
          by (auto simp add: clauseFalseIffAllLiteralsAreFalse inconsistentCharacterization)      
          ultimately
          show ?thesis
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(3) Cons(4) Cons(6)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            using ‹uniq Wl'
            apply (simp add: Let_def)
            unfolding setReason_def
            unfolding swapWatches_def
            by auto
        qed
      qed
    qed
  next
    case False
    let ?state' = state
    let ?w1 = wa
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch1 state clause = Some wa
      unfolding swapWatches_def
      by auto
    let ?w2 = wb
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch2 state clause = Some wb
      unfolding swapWatches_def
      by auto

    from ¬ Some literal = getWatch1 state clause
       (c::nat). c  set (clause # Wl')  Some literal = (getWatch1 state c)   Some literal = (getWatch2 state c)
    have "Some literal = getWatch2 state clause"
      by auto
    hence "literalFalse ?w2 (elements (getM state))"
      using 
      ‹getWatch2 ?state' clause = Some ?w2
      ‹literalFalse literal (elements (getM state))
      by simp

    from ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)
    have "?w1 el (nth (getF state) clause)"
      using ‹getWatch1 ?state' clause = Some ?w1
      using ‹getWatch2 ?state' clause = Some ?w2
      using clause < length (getF state)
      unfolding InvariantWatchesEl_def
      unfolding swapWatches_def
      by auto
    
    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True

      have "¬ clauseFalse (nth (getF state) clause) (elements (getM state))"
        using ?w1 el (nth (getF state) clause)
        using ‹literalTrue ?w1 (elements (getM ?state'))
        using ‹InvariantConsistent (getM state)
        unfolding InvariantConsistent_def
        unfolding swapWatches_def
        by (auto simp add: clauseFalseIffAllLiteralsAreFalse inconsistentCharacterization)

      thus ?thesis
        using True
        using Cons(1)[of "?state'" "clause # newWl"]
        using Cons(2) Cons(3) Cons(4) Cons(5) Cons(6)
        using ¬ Some literal = getWatch1 state clause
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹literalTrue ?w1 (elements (getM ?state'))
        using ‹uniq Wl'
        by (auto simp add:Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state') clause)" "¬ literalFalse l' (elements (getM ?state'))"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by auto

        let ?state'' = "setWatch2 clause l' ?state'"

        from Cons(2)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state') clause)
          unfolding InvariantWatchesEl_def
          unfolding setWatch2_def
          by auto
        moreover
        from Cons(4)
        have "InvariantConsistent (getM ?state'')"
          unfolding setWatch2_def
          by simp
        moreover
        have "getM ?state'' = getM state 
          getF ?state'' = getF state  
          getConflictFlag ?state'' = getConflictFlag state"
          unfolding setWatch2_def
          by simp
        moreover
        have "c. c  set Wl'  Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c"
          using Cons(5)
          using clause  set Wl'
          unfolding setWatch2_def
          by auto
        moreover
        have "¬ clauseFalse (nth (getF state) clause) (elements (getM state))"
          using l' el (nth (getF ?state') clause) 
          using ¬ literalFalse l' (elements (getM ?state'))
          using ‹InvariantConsistent (getM state)
          unfolding InvariantConsistent_def
          by (auto simp add: clauseFalseIffAllLiteralsAreFalse inconsistentCharacterization)
        ultimately
        show ?thesis
          using Cons(1)[of "?state''" "newWl"]
          using Cons(3) Cons(4) Cons(6)
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ¬ Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using ‹uniq Wl'
          using Some
          by (auto simp add: Let_def)
      next
        case None
        hence " l. l el (nth (getF ?state') clause)  l  ?w1  l  ?w2  literalFalse l (elements (getM ?state'))"
          using getNonWatchedUnfalsifiedLiteralNoneCharacterization
          by simp
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            by auto
          moreover
          from Cons(4)
          have "InvariantConsistent (getM ?state'')"
            unfolding setWatch2_def
            by simp
          moreover
          have "getM ?state'' = getM state 
          getF ?state'' = getF state  
          getSATFlag ?state'' = getSATFlag state"
            by simp
          moreover
          have "c. c  set Wl'  Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c"
            using Cons(5)
            using clause  set Wl'
            unfolding setWatch2_def
            by auto
          moreover
          have "clauseFalse (nth (getF state) clause) (elements (getM state))"
            using  l. l el (nth (getF ?state') clause)  l  ?w1  l  ?w2  literalFalse l (elements (getM ?state'))
            using ‹literalFalse ?w1 (elements (getM ?state'))
            using ‹literalFalse ?w2 (elements (getM state))
            by (auto simp add: clauseFalseIffAllLiteralsAreFalse)
          ultimately
          show ?thesis
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(3) Cons(4) Cons(6)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ¬ Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            using ‹uniq Wl'
            by (auto simp add: Let_def)
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"

          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding setReason_def
            by auto
          moreover
          from Cons(4)
          have "InvariantConsistent (getM ?state'')"
            unfolding setReason_def
            by simp
          moreover
          have "getM ?state'' = getM state 
            getF ?state'' = getF state  
            getSATFlag ?state'' = getSATFlag state"
            unfolding setReason_def
            by simp
          moreover
          have "c. c  set Wl'  Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c"
            using Cons(5)
            using clause  set Wl'
            unfolding setReason_def
            by auto
          moreover
          have "¬ clauseFalse (nth (getF state) clause) (elements (getM state))"
            using ?w1 el (nth (getF state) clause)
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            using ‹InvariantConsistent (getM state)
            unfolding InvariantConsistent_def
          by (auto simp add: clauseFalseIffAllLiteralsAreFalse inconsistentCharacterization)      
          ultimately
          show ?thesis
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(3) Cons(4) Cons(6)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ¬ Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            using ‹uniq Wl'
            apply (simp add: Let_def)
            unfolding setReason_def
            by auto
        qed
      qed
    qed
  qed
qed


lemma NotifyWatchesLoopQEffect:
fixes literal :: Literal and Wl :: "nat list" and newWl :: "nat list" and state :: State
assumes 
  "(getM state) = M @ [(opposite literal, decision)]" and
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and 
  " (c::nat). c  set Wl  0  c  c < length (getF state)" and
  "InvariantConsistent (getM state)" and
  " (c::nat). c  set Wl  Some literal = (getWatch1 state c)   Some literal = (getWatch2 state c)" and
  "uniq Wl" and
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) M"
shows
  "let state' = notifyWatches_loop literal Wl newWl state in
      (( l. l  (set (getQ state') - set (getQ state))  
            ( clause. (clause el (getF state) 
                        literal el clause 
                        (isUnitClause clause l (elements (getM state)))))) 
      ( clause. clause  set Wl  
          ( l. (isUnitClause (nth (getF state) clause) l (elements (getM state)))  
                     l  (set (getQ state')))))" 
  (is "let state' = notifyWatches_loop literal Wl newWl state in (?Cond1 state' state  ?Cond2 Wl state' state)")
using assms
proof (induct Wl arbitrary: newWl state)
  case Nil
  thus ?case
    by simp
next
  case (Cons clause Wl')
  
  from ‹uniq (clause # Wl')
  have "uniq Wl'" and "clause  set Wl'"
    by (auto simp add: uniqAppendIff)

  from  (c::nat). c  set (clause # Wl')  0  c  c < length (getF state)
  have "0  clause" "clause < length (getF state)"
    by auto
  then obtain wa::Literal and wb::Literal
    where "getWatch1 state clause = Some wa" and "getWatch2 state clause = Some wb"
    using Cons
    unfolding InvariantWatchesEl_def
    by auto

  from 0  clause clause < length (getF state)
  have "(nth (getF state) clause) el (getF state)"
    by simp

  show ?case
  proof (cases "Some literal = getWatch1 state clause")
    case True
    let ?state' = "swapWatches clause state"
    let ?w1 = wb
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch2 state clause = Some wb
      unfolding swapWatches_def
      by auto
    let ?w2 = wa
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch1 state clause = Some wa
      unfolding swapWatches_def
      by auto

    have "?w2 = literal"
      using ‹Some literal = getWatch1 state clause
      using ‹getWatch2 ?state' clause = Some ?w2
      unfolding swapWatches_def
      by simp
      
    hence "literalFalse ?w2 (elements (getM state))"
      using (getM state) = M @ [(opposite literal, decision)]
      by simp

    from ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)
    have "?w1 el (nth (getF state) clause)" "?w2 el (nth (getF state) clause)"
      using ‹getWatch1 ?state' clause = Some ?w1
      using ‹getWatch2 ?state' clause = Some ?w2
      using clause < length (getF state)
      unfolding InvariantWatchesEl_def
      unfolding swapWatches_def
      by auto

    from ‹InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)
    have "?w1  ?w2"
      using ‹getWatch1 ?state' clause = Some ?w1
      using ‹getWatch2 ?state' clause = Some ?w2
      using clause < length (getF state)
      unfolding InvariantWatchesDiffer_def
      unfolding swapWatches_def
      by auto

    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True
      
      from Cons(3)
      have "InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
        unfolding InvariantWatchesEl_def
        unfolding swapWatches_def
        by auto
      moreover
      from Cons(4)
      have "InvariantWatchesDiffer (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
        unfolding InvariantWatchesDiffer_def
        unfolding swapWatches_def
        by auto
      moreover
      have "getF ?state' = getF state  
        getM ?state' = getM state  
        getQ ?state' = getQ state  
        getConflictFlag ?state' = getConflictFlag state
        "
        unfolding swapWatches_def
        by simp
      moreover
      have "c. c  set Wl'  Some literal = getWatch1 ?state' c  Some literal = getWatch2 ?state' c"
        using Cons(7)
        unfolding swapWatches_def
        by auto
      moreover
      have "InvariantWatchCharacterization (getF ?state') (getWatch1 ?state') (getWatch2 ?state') M"
        using Cons(9)
        unfolding swapWatches_def
        unfolding InvariantWatchCharacterization_def
        by auto
      moreover
      have "¬ ( l. isUnitClause (nth (getF state) clause) l (elements (getM state)))"
        using ?w1 el (nth (getF state) clause)
        using ‹literalTrue ?w1 (elements (getM ?state'))
        using ‹InvariantConsistent (getM state)
        unfolding InvariantConsistent_def
        unfolding swapWatches_def
          by (auto simp add: isUnitClause_def inconsistentCharacterization)
      ultimately
      show ?thesis
        using Cons(1)[of "?state'" "clause # newWl"]
        using Cons(2) Cons(5) Cons(6)
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹Some literal = getWatch1 state clause
        using ‹literalTrue ?w1 (elements (getM ?state'))
        using ‹uniq Wl'
        by ( simp add:Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state') clause)" "¬ literalFalse l' (elements (getM ?state'))" "l'  ?w1" "l'  ?w2"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by auto

        let ?state'' = "setWatch2 clause l' ?state'"

        from Cons(3)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state') clause)
          unfolding InvariantWatchesEl_def
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        moreover
        from Cons(4)
        have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l'  ?w1
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          unfolding InvariantWatchesDiffer_def
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        moreover
        from Cons(6)
        have "InvariantConsistent (getM ?state'')"
          unfolding setWatch2_def
          unfolding swapWatches_def
          by simp
        moreover
        have "getM ?state'' = getM state 
          getF ?state'' = getF state  
          getQ ?state'' = getQ state  
          getConflictFlag ?state'' = getConflictFlag state"
          unfolding swapWatches_def
          unfolding setWatch2_def
          by simp
        moreover
        have "c. c  set Wl'  Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c"
          using Cons(7)
          using clause  set Wl'
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        moreover
        have "InvariantWatchCharacterization (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') M"
        proof-
          {
            fix c::nat and ww1::Literal and ww2::Literal
            assume a: "0  c  c < length (getF ?state'')  Some ww1 = (getWatch1 ?state'' c)  Some ww2 = (getWatch2 ?state'' c)"
            assume b: "literalFalse ww1 (elements M)"
              
            have "(l. l el ((getF ?state'') ! c)  literalTrue l (elements M)  elementLevel l M  elementLevel (opposite ww1) M) 
                  (l. l el ((getF ?state'') ! c)  l  ww1  l  ww2  
                       literalFalse l (elements M)  elementLevel (opposite l) M  elementLevel (opposite ww1) M)"
            proof (cases "c = clause")
              case False
              thus ?thesis
                using a and b
                using Cons(9)
                unfolding InvariantWatchCharacterization_def
                unfolding watchCharacterizationCondition_def
                unfolding swapWatches_def
                unfolding setWatch2_def
                by simp
            next
              case True
              with a 
              have "ww1 = ?w1" and "ww2 = l'"
                using ‹getWatch1 ?state' clause = Some ?w1
                using ‹getWatch2 ?state' clause = Some ?w2[THEN sym]
                unfolding setWatch2_def
                unfolding swapWatches_def
                by auto
              
              have "¬ (l. l el (getF state ! clause)  l  ?w1  l  ?w2  literalFalse l (elements M))"
                using Cons(2)
                using l'  ?w1 and l'  ?w2 l' el (nth (getF ?state') clause)
                using ¬ literalFalse l' (elements (getM ?state'))
                using a and b
                using c = clause
                unfolding swapWatches_def
                unfolding setWatch2_def
                by auto
              moreover
              have "(l. l el (getF state ! clause)  literalTrue l (elements M)  
                elementLevel l M  elementLevel (opposite ?w1) M) 
                (l. l el (getF state ! clause)  l  ?w1  l  ?w2  literalFalse l (elements M))"
                using Cons(9)
                unfolding InvariantWatchCharacterization_def
                unfolding watchCharacterizationCondition_def
                using clause < length (getF state)
                using ‹getWatch1 ?state' clause = Some ?w1[THEN sym]
                using ‹getWatch2 ?state' clause = Some ?w2[THEN sym]
                using ‹literalFalse ww1 (elements M)
                using ww1 = ?w1
                unfolding setWatch2_def
                unfolding swapWatches_def
                by auto
              ultimately
              show ?thesis
                using ww1 = ?w1
                using c = clause
                unfolding setWatch2_def
                unfolding swapWatches_def
                by auto
            qed
          }
          moreover 
          {
            fix c::nat and ww1::Literal and ww2::Literal
            assume a: "0  c  c < length (getF ?state'')  Some ww1 = (getWatch1 ?state'' c)  Some ww2 = (getWatch2 ?state'' c)"
            assume b: "literalFalse ww2 (elements M)"
            
            have "(l. l el ((getF ?state'') ! c)  literalTrue l (elements M)  elementLevel l M  elementLevel (opposite ww2) M) 
                  (l. l el ((getF ?state'') ! c)  l  ww1  l  ww2  
                       literalFalse l (elements M)  elementLevel (opposite l) M  elementLevel (opposite ww2) M)"
            proof (cases "c = clause")
              case False
              thus ?thesis
                using a and b
                using Cons(9)
                unfolding InvariantWatchCharacterization_def
                unfolding watchCharacterizationCondition_def
                unfolding swapWatches_def
                unfolding setWatch2_def
                by auto
            next
              case True
              with a 
              have "ww1 = ?w1" and "ww2 = l'"
                using ‹getWatch1 ?state' clause = Some ?w1
                using ‹getWatch2 ?state' clause = Some ?w2[THEN sym]
                unfolding setWatch2_def
                unfolding swapWatches_def
                by auto
              with ¬ literalFalse l' (elements (getM ?state')) b
                Cons(2)
              have False
                unfolding swapWatches_def
                by simp
              thus ?thesis
                by simp
            qed
          }
          ultimately
          show ?thesis
            unfolding InvariantWatchCharacterization_def
            unfolding watchCharacterizationCondition_def
            by blast
        qed
        moreover
        have "¬ ( l. isUnitClause (nth (getF state) clause) l (elements (getM state)))"
          (* Depends on the watch characterization invariant *)
        proof-
          {
            assume "¬ ?thesis"
            then obtain l
              where "isUnitClause (nth (getF state) clause) l (elements (getM state))"
              by auto
            with l' el (nth (getF ?state') clause) ¬ literalFalse l' (elements (getM ?state'))
            have "l = l'"
              unfolding isUnitClause_def
              unfolding swapWatches_def
              by auto
            with l'  ?w1 have
              "literalFalse ?w1 (elements (getM ?state'))"
              using ‹isUnitClause (nth (getF state) clause) l (elements (getM state))
              using ?w1 el (nth (getF state) clause)
              unfolding isUnitClause_def
              unfolding swapWatches_def
              by simp
            with ?w1  ?w2 ?w2 = literal
            Cons(2)
            have "literalFalse ?w1 (elements M)"
              unfolding swapWatches_def
              by simp

            from ‹isUnitClause (nth (getF state) clause) l (elements (getM state))
              Cons(6)
            have "¬ ( l. (l el (nth (getF state) clause)  literalTrue l (elements (getM state))))"
              using containsTrueNotUnit[of _ "(nth (getF state) clause)" "elements (getM state)"]
              unfolding InvariantConsistent_def
              by auto

            from ‹InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) M
            clause < length (getF state)
              ‹literalFalse ?w1 (elements M) 
              ‹getWatch1 ?state' clause = Some ?w1 [THEN sym]
              ‹getWatch2 ?state' clause = Some ?w2 [THEN sym]
            have "(l. l el (getF state ! clause)  literalTrue l (elements M)  elementLevel l M  elementLevel (opposite ?w1) M) 
                  (l. l el (getF state ! clause)  l  ?w1  l  ?w2  literalFalse l (elements M))"
              unfolding InvariantWatchCharacterization_def
              unfolding watchCharacterizationCondition_def
              unfolding swapWatches_def
              by auto
            with ¬ ( l. (l el (nth (getF state) clause)  literalTrue l (elements (getM state))))
            Cons(2)
            have "(l. l el (getF state ! clause)  l  ?w1  l  ?w2  literalFalse l (elements M))"
              by auto
            with l' el (getF ?state' ! clause) l'  ?w1 l'  ?w2 ¬ literalFalse l' (elements (getM ?state'))
            Cons(2)
            have False
              unfolding swapWatches_def
              by simp
          }
          thus ?thesis
            by auto
        qed
        ultimately
        show ?thesis
          using Cons(1)[of "?state''" "newWl"]
          using Cons(2) Cons(5) Cons(6)
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ‹Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using ‹uniq Wl'
          using Some
          by (simp add: Let_def)
      next
        case None
        hence " l. l el (nth (getF ?state') clause)  l  ?w1  l  ?w2  literalFalse l (elements (getM ?state'))"
          using getNonWatchedUnfalsifiedLiteralNoneCharacterization
          by simp
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons(3)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            by auto
          moreover
          from Cons(4)
          have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesDiffer_def
            unfolding swapWatches_def
            by auto
          moreover
          from Cons(6)
          have "InvariantConsistent (getM ?state'')"
            unfolding swapWatches_def
            by simp
          moreover
          have "getM ?state'' = getM state 
          getF ?state'' = getF state  
          getQ ?state'' = getQ state  
          getSATFlag ?state'' = getSATFlag state"
            unfolding swapWatches_def
            by simp
          moreover
          have "c. c  set Wl'  Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c"
            using Cons(7)
            using clause  set Wl'
            unfolding swapWatches_def
            by auto
          moreover
          have "InvariantWatchCharacterization (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') M"
            using Cons(9)
            unfolding swapWatches_def
            unfolding InvariantWatchCharacterization_def
            by auto
          moreover
          have "clauseFalse (nth (getF state) clause) (elements (getM state))"
            using  l. l el (nth (getF ?state') clause)  l  ?w1  l  ?w2  literalFalse l (elements (getM ?state'))
            using ‹literalFalse ?w1 (elements (getM ?state'))
            using ‹literalFalse ?w2 (elements (getM state))
            unfolding swapWatches_def
            by (auto simp add: clauseFalseIffAllLiteralsAreFalse)
          hence "¬ ( l. isUnitClause (nth (getF state) clause) l (elements (getM state)))"
            unfolding isUnitClause_def
            by (simp add: clauseFalseIffAllLiteralsAreFalse)
          ultimately
          show ?thesis
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(2) Cons(5) Cons(6)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            using ‹uniq Wl'
            by (simp add: Let_def)
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"

          from Cons(3)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          from Cons(4)
          have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesDiffer_def
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          from Cons(6)
          have "InvariantConsistent (getM ?state'')"
            unfolding swapWatches_def
            unfolding setReason_def
            by simp
          moreover
          have "getM ?state'' = getM state 
            getF ?state'' = getF state  
            getSATFlag ?state'' = getSATFlag state  
            getQ ?state'' = (if ?w1 el (getQ state) then (getQ state) else (getQ state @ [?w1]))"
            unfolding swapWatches_def
            unfolding setReason_def
            by simp
          moreover
          have "c. c  set Wl'  Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c"
            using Cons(7)
            using clause  set Wl'
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          have "InvariantWatchCharacterization (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') M"
            using Cons(9)
            unfolding swapWatches_def
            unfolding setReason_def
            unfolding InvariantWatchCharacterization_def
            by auto
          ultimately
          have "let state' = notifyWatches_loop literal Wl' (clause # newWl) ?state'' in 
                   ?Cond1 state' ?state''  ?Cond2 Wl' state' ?state''"
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(2) Cons(5)
            using ‹uniq Wl'
            by (simp add: Let_def)
          moreover
          have "notifyWatches_loop literal Wl' (clause # newWl) ?state'' = notifyWatches_loop literal (clause # Wl') newWl state"
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            by (simp add: Let_def)
          ultimately 
          have "let state' = notifyWatches_loop literal (clause # Wl') newWl state in
                   ?Cond1 state' ?state''  ?Cond2 Wl' state' ?state''"
            by simp

          have "isUnitClause (nth (getF state) clause) ?w1 (elements (getM state))"
            using  l. l el (nth (getF ?state') clause)  l  ?w1  l  ?w2  literalFalse l (elements (getM ?state'))
            using ?w1 el (nth (getF state) clause)
            using ?w2 el (nth (getF state) clause)
            using ‹literalFalse ?w2 (elements (getM state))
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            unfolding swapWatches_def
            unfolding isUnitClause_def
            by auto

          show ?thesis
          proof-
            {
              fix l::Literal
              assume "let state' = notifyWatches_loop literal (clause # Wl') newWl state in
                l  set (getQ state') - set (getQ state)"
              have "clause. clause el (getF state)  literal el clause  isUnitClause clause l (elements (getM state))"
              proof (cases "l  ?w1")
                case True
                hence "let state' = notifyWatches_loop literal (clause # Wl') newWl state in 
                   l  set (getQ state') - set (getQ ?state'')"
                  using let state' = notifyWatches_loop literal (clause # Wl') newWl state in
                    l  set (getQ state') - set (getQ state)
                  unfolding setReason_def
                  unfolding swapWatches_def
                  by (simp add:Let_def)
                with let state' = notifyWatches_loop literal (clause # Wl') newWl state in
                  ?Cond1 state' ?state''  ?Cond2 Wl' state' ?state''
                show ?thesis
                  unfolding setReason_def
                  unfolding swapWatches_def
                  by (simp add:Let_def del: notifyWatches_loop.simps)
              next
                case False
                thus ?thesis
                  using (nth (getF state) clause) el (getF state)
                        ?w2 = literal
                        ?w2 el (nth (getF state) clause)
                        ‹isUnitClause (nth (getF state) clause) ?w1 (elements (getM state))
                  by (auto simp add:Let_def)
              qed
            } 
            hence "let state' = notifyWatches_loop literal (clause # Wl') newWl state in
                ?Cond1 state' state"
              by simp
            moreover
            {
              fix c
              assume "c  set (clause # Wl')"
              have "let state' = notifyWatches_loop literal (clause # Wl') newWl state in 
                 l. isUnitClause (nth (getF state) c) l (elements (getM state))  l  set (getQ state')"
              proof (cases "c = clause")
                case True
                {
                  fix l::Literal
                  assume "isUnitClause (nth (getF state) c) l (elements (getM state))"
                  with ‹isUnitClause (nth (getF state) clause) ?w1 (elements (getM state)) c = clause
                  have "l = ?w1"
                    unfolding isUnitClause_def
                    by auto
                  have "isPrefix (getQ ?state'') (getQ (notifyWatches_loop literal Wl' (clause # newWl) ?state''))"
                    using ‹InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')
                    using notifyWatchesLoopPreservedVariables[of "?state''" "Wl'" "literal" "clause # newWl"]
                    using Cons(5)
                    unfolding swapWatches_def
                    unfolding setReason_def
                    by (simp add: Let_def)
                  hence "set (getQ ?state'')  set (getQ (notifyWatches_loop literal Wl' (clause # newWl) ?state''))"
                    using prefixIsSubset[of "getQ ?state''" "getQ (notifyWatches_loop literal Wl' (clause # newWl) ?state'')"]
                    by auto
                  hence "l  set (getQ (notifyWatches_loop literal Wl' (clause # newWl) ?state''))"
                    using l = ?w1
                    unfolding swapWatches_def
                    unfolding setReason_def
                  by auto
              } 
              thus ?thesis
                using ‹notifyWatches_loop literal Wl' (clause # newWl) ?state'' = notifyWatches_loop literal (clause # Wl') newWl state
                by (simp add:Let_def)
            next
                case False
                hence "c  set Wl'"
                  using c  set (clause # Wl')
                  by simp
                {
                  fix l::Literal
                  assume "isUnitClause (nth (getF state) c) l (elements (getM state))"
                  hence "isUnitClause (nth (getF ?state'') c) l (elements (getM ?state''))"
                    unfolding setReason_def
                    unfolding swapWatches_def
                    by simp
                  with let state' = notifyWatches_loop literal (clause # Wl') newWl state in
                    ?Cond1 state' ?state''  ?Cond2 Wl' state' ?state''
                    c  set Wl'
                  have "let state' = notifyWatches_loop literal (clause # Wl') newWl state in l  set (getQ state')"
                    by (simp add:Let_def)
                }
                thus ?thesis
                  by (simp add:Let_def)
              qed
            }
            hence "?Cond2 (clause # Wl') (notifyWatches_loop literal (clause # Wl') newWl state) state"
              by (simp add: Let_def)
            ultimately
            show ?thesis
              by (simp add:Let_def)
          qed
        qed
      qed
    qed
  next
    case False
    let ?state' = state
    let ?w1 = wa
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch1 state clause = Some wa
      unfolding swapWatches_def
      by auto
    let ?w2 = wb
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch2 state clause = Some wb
      unfolding swapWatches_def
      by auto


    from ¬ Some literal = getWatch1 state clause
       (c::nat). c  set (clause # Wl')  Some literal = (getWatch1 state c)   Some literal = (getWatch2 state c)
    have "Some literal = getWatch2 state clause"
      by auto
    hence "?w2 = literal"
      using ‹getWatch2 ?state' clause = Some ?w2
      by simp
    hence "literalFalse ?w2 (elements (getM state))"
      using Cons(2)
      by simp

    from ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)
    have "?w1 el (nth (getF state) clause)" "?w2 el (nth (getF state) clause)"
      using ‹getWatch1 ?state' clause = Some ?w1
      using ‹getWatch2 ?state' clause = Some ?w2
      using clause < length (getF state)
      unfolding InvariantWatchesEl_def
      unfolding swapWatches_def
      by auto

    from ‹InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)
    have "?w1  ?w2"
      using ‹getWatch1 ?state' clause = Some ?w1
      using ‹getWatch2 ?state' clause = Some ?w2
      using clause < length (getF state)
      unfolding InvariantWatchesDiffer_def
      unfolding swapWatches_def
      by auto
    
    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True
      have "¬ ( l. isUnitClause (nth (getF state) clause) l (elements (getM state)))"
        using ?w1 el (nth (getF state) clause)
        using ‹literalTrue ?w1 (elements (getM ?state'))
        using ‹InvariantConsistent (getM state)
        unfolding InvariantConsistent_def
        by (auto simp add: isUnitClause_def inconsistentCharacterization)
      thus ?thesis
        using True
        using Cons(1)[of "?state'" "clause # newWl"]
        using Cons(2) Cons(3) Cons(4) Cons(5) Cons(6) Cons(7) Cons(8) Cons(9)
        using ¬ Some literal = getWatch1 state clause
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹literalTrue ?w1 (elements (getM ?state'))
        using ‹uniq Wl'
        by (simp add:Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state') clause)" "¬ literalFalse l' (elements (getM ?state'))" "l'  ?w1" "l'  ?w2"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by auto

        let ?state'' = "setWatch2 clause l' ?state'"

        from Cons(3)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state') clause)
          unfolding InvariantWatchesEl_def
          unfolding setWatch2_def
          by auto
        moreover
        from Cons(4)
        have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l'  ?w1
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          unfolding InvariantWatchesDiffer_def
          unfolding setWatch2_def
          by auto
        moreover
        from Cons(6)
        have "InvariantConsistent (getM ?state'')"
          unfolding setWatch2_def
          by simp
        moreover
        have "getM ?state'' = getM state 
          getF ?state'' = getF state  
          getQ ?state'' = getQ state  
          getConflictFlag ?state'' = getConflictFlag state"
          unfolding setWatch2_def
          by simp
        moreover
        have "c. c  set Wl'  Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c"
          using Cons(7)
          using clause  set Wl'
          unfolding setWatch2_def
          by auto
        moreover
        have "InvariantWatchCharacterization (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') M"
        proof-
          {
            fix c::nat and ww1::Literal and ww2::Literal
            assume a: "0  c  c < length (getF ?state'')  Some ww1 = (getWatch1 ?state'' c)  Some ww2 = (getWatch2 ?state'' c)"
            assume b: "literalFalse ww1 (elements M)"
              
            have "(l.  l el ((getF ?state'') ! c)  literalTrue l (elements M)  elementLevel l M  elementLevel (opposite ww1) M) 
              (l. l el (getF ?state'' ! c)  l  ww1  l  ww2  
                   literalFalse l (elements M)  elementLevel (opposite l) M  elementLevel (opposite ww1) M)"
            proof (cases "c = clause")
              case False
              thus ?thesis
                using a and b
                using Cons(9)
                unfolding InvariantWatchCharacterization_def
                unfolding watchCharacterizationCondition_def
                unfolding setWatch2_def
                by auto
            next
              case True
              with a 
              have "ww1 = ?w1" and "ww2 = l'"
                using ‹getWatch1 ?state' clause = Some ?w1
                using ‹getWatch2 ?state' clause = Some ?w2[THEN sym]
                unfolding setWatch2_def
                by auto
              
              have "¬ (l. l el (getF state ! clause)  l  ?w1  l  ?w2  literalFalse l (elements M))"
                using l'  ?w1 and l'  ?w2 l' el (nth (getF ?state') clause)
                using ¬ literalFalse l' (elements (getM ?state'))
                using Cons(2)
                using a and b
                using c = clause
                unfolding setWatch2_def
                by auto
              moreover
              have "(l. l el (getF state ! clause)  literalTrue l (elements M)  elementLevel l M  elementLevel (opposite ?w1) M) 
                    (l. l el (getF state ! clause)  l  ?w1  l  ?w2  literalFalse l (elements M))"
                using Cons(9)
                unfolding InvariantWatchCharacterization_def
                unfolding watchCharacterizationCondition_def
                using clause < length (getF state)
                using ‹getWatch1 ?state' clause = Some ?w1[THEN sym]
                using ‹getWatch2 ?state' clause = Some ?w2[THEN sym]
                using ‹literalFalse ww1 (elements M)
                using ww1 = ?w1
                unfolding setWatch2_def
                by auto
              ultimately
              show ?thesis
                using ww1 = ?w1
                using c = clause
                unfolding setWatch2_def
                by auto
            qed
          }
          moreover 
          {
            fix c::nat and ww1::Literal and ww2::Literal
            assume a: "0  c  c < length (getF ?state'')  Some ww1 = (getWatch1 ?state'' c)  Some ww2 = (getWatch2 ?state'' c)"
            assume b: "literalFalse ww2 (elements M)"
            
            have "(l.  l el ((getF ?state'') ! c)  literalTrue l (elements M)  elementLevel l M  elementLevel (opposite ww2) M) 
              (l. l el (getF ?state'' ! c)  l  ww1  l  ww2  
                   literalFalse l (elements M)  elementLevel (opposite l) M  elementLevel (opposite ww2) M)"
            proof (cases "c = clause")
              case False
              thus ?thesis
                using a and b
                using Cons(9)
                unfolding InvariantWatchCharacterization_def
                unfolding watchCharacterizationCondition_def
                unfolding setWatch2_def
                by auto
            next
              case True
              with a 
              have "ww1 = ?w1" and "ww2 = l'"
                using ‹getWatch1 ?state' clause = Some ?w1
                using ‹getWatch2 ?state' clause = Some ?w2[THEN sym]
                unfolding setWatch2_def
                by auto
              with ¬ literalFalse l' (elements (getM ?state')) b
              Cons(2)
              have False
                unfolding setWatch2_def
                by simp
              thus ?thesis
                by simp
            qed
          }
          ultimately
          show ?thesis
            unfolding InvariantWatchCharacterization_def
            unfolding watchCharacterizationCondition_def
            by blast
        qed
        moreover
        have "¬ ( l. isUnitClause (nth (getF state) clause) l (elements (getM state)))"
          (* Depends on the watch characterization invariant *)
        proof-
          {
            assume "¬ ?thesis"
            then obtain l
              where "isUnitClause (nth (getF state) clause) l (elements (getM state))"
              by auto
            with l' el (nth (getF ?state') clause) ¬ literalFalse l' (elements (getM ?state'))
            have "l = l'"
              unfolding isUnitClause_def
              by auto
            with l'  ?w1 have
              "literalFalse ?w1 (elements (getM ?state'))"
              using ‹isUnitClause (nth (getF state) clause) l (elements (getM state))
              using ?w1 el (nth (getF state) clause)
              unfolding isUnitClause_def
              by simp
            with ?w1  ?w2 ?w2 = literal
            Cons(2)
            have "literalFalse ?w1 (elements M)"
              by simp

            from ‹isUnitClause (nth (getF state) clause) l (elements (getM state))
              Cons(6)
            have "¬ ( l. (l el (nth (getF state) clause)  literalTrue l (elements (getM state))))"
              using containsTrueNotUnit[of _ "(nth (getF state) clause)" "elements (getM state)"]
              unfolding InvariantConsistent_def
              by auto

            from ‹InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) M
            clause < length (getF state)
              ‹literalFalse ?w1 (elements M) 
              ‹getWatch1 ?state' clause = Some ?w1 [THEN sym]
              ‹getWatch2 ?state' clause = Some ?w2 [THEN sym]
            have "(l. l el (getF state ! clause)  literalTrue l (elements M)  elementLevel l M  elementLevel (opposite ?w1) M) 
                  (l. l el (getF state ! clause)  l  ?w1  l  ?w2  literalFalse l (elements M))"
              unfolding InvariantWatchCharacterization_def
              unfolding watchCharacterizationCondition_def
              unfolding swapWatches_def
              by auto
            with ¬ ( l. (l el (nth (getF state) clause)  literalTrue l (elements (getM state))))
            Cons(2)
            have "(l. l el (getF state ! clause)  l  ?w1  l  ?w2  literalFalse l (elements M))"
              by auto
            with l' el (getF ?state' ! clause) l'  ?w1 l'  ?w2 ¬ literalFalse l' (elements (getM ?state'))
            Cons(2)
            have False
              unfolding swapWatches_def
              by simp
          }
          thus ?thesis
            by auto
        qed
        ultimately
        show ?thesis
          using Cons(1)[of "?state''" "newWl"]
          using Cons(2) Cons(5) Cons(7)
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ¬ Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using ‹uniq Wl'
          using Some
          by (simp add: Let_def)
      next
        case None
        hence " l. l el (nth (getF ?state') clause)  l  ?w1  l  ?w2  literalFalse l (elements (getM ?state'))"
          using getNonWatchedUnfalsifiedLiteralNoneCharacterization
          by simp
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons(3)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            by auto
          moreover
          from Cons(4)
          have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesDiffer_def
            by auto
          moreover
          from Cons(6)
          have "InvariantConsistent (getM ?state'')"
            unfolding setWatch2_def
            by simp
          moreover
          have "getM ?state'' = getM state 
          getF ?state'' = getF state  
          getSATFlag ?state'' = getSATFlag state"
            by simp
          moreover
          have "c. c  set Wl'  Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c"
            using Cons(7)
            using clause  set Wl'
            unfolding setWatch2_def
            by auto
          moreover
          have "InvariantWatchCharacterization (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') M"
            using Cons(9)
            unfolding InvariantWatchCharacterization_def
            by auto
          moreover
          have "clauseFalse (nth (getF state) clause) (elements (getM state))"
            using  l. l el (nth (getF ?state') clause)  l  ?w1  l  ?w2  literalFalse l (elements (getM ?state'))
            using ‹literalFalse ?w1 (elements (getM ?state'))
            using ‹literalFalse ?w2 (elements (getM state))
            unfolding swapWatches_def
            by (auto simp add: clauseFalseIffAllLiteralsAreFalse)
          hence "¬ ( l. isUnitClause (nth (getF state) clause) l (elements (getM state)))"
            unfolding isUnitClause_def
            by (simp add: clauseFalseIffAllLiteralsAreFalse)
          ultimately
          show ?thesis
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(2) Cons(5) Cons(7)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ¬ Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            using ‹uniq Wl'
            by (simp add: Let_def)
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"

          from Cons(3)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding setReason_def
            by auto
          moreover
          from Cons(4)
          have "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesDiffer_def
            unfolding setReason_def
            by auto
          moreover
          from Cons(6)
          have "InvariantConsistent (getM ?state'')"
            unfolding setReason_def
            by simp
          moreover
          have "getM ?state'' = getM state 
            getF ?state'' = getF state  
            getSATFlag ?state'' = getSATFlag state"
            unfolding setReason_def
            by simp
          moreover
          have "c. c  set Wl'  Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c"
            using Cons(7)
            using clause  set Wl'
            unfolding setReason_def
            by auto
          moreover
          have "InvariantWatchCharacterization (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') M"
            using Cons(9)
            unfolding InvariantWatchCharacterization_def
            unfolding setReason_def
            by auto
          ultimately
          have "let state' = notifyWatches_loop literal Wl' (clause # newWl) ?state'' in 
                   ?Cond1 state' ?state''  ?Cond2 Wl' state' ?state''"
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(2) Cons(5) Cons(6) Cons(7)
            using ‹uniq Wl'
            by (simp add: Let_def)
          moreover
          have "notifyWatches_loop literal Wl' (clause # newWl) ?state'' = notifyWatches_loop literal (clause # Wl') newWl state"
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ¬ Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            by (simp add: Let_def)
          ultimately 
          have "let state' = notifyWatches_loop literal (clause # Wl') newWl state in
                   ?Cond1 state' ?state''  ?Cond2 Wl' state' ?state''"
            by simp

          have "isUnitClause (nth (getF state) clause) ?w1 (elements (getM state))"
            using  l. l el (nth (getF ?state') clause)  l  ?w1  l  ?w2  literalFalse l (elements (getM ?state'))
            using ?w1 el (nth (getF state) clause)
            using ?w2 el (nth (getF state) clause)
            using ‹literalFalse ?w2 (elements (getM state))
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            unfolding swapWatches_def
            unfolding isUnitClause_def
            by auto

          show ?thesis
          proof-
            {
              fix l::Literal
              assume "let state' = notifyWatches_loop literal (clause # Wl') newWl state in
                l  set (getQ state') - set (getQ state)"
              have "clause. clause el (getF state)  literal el clause  isUnitClause clause l (elements (getM state))"
              proof (cases "l  ?w1")
                case True
                hence "let state' = notifyWatches_loop literal (clause # Wl') newWl state in 
                   l  set (getQ state') - set (getQ ?state'')"
                  using let state' = notifyWatches_loop literal (clause # Wl') newWl state in
                    l  set (getQ state') - set (getQ state)
                  unfolding setReason_def
                  unfolding swapWatches_def
                  by (simp add:Let_def)
                with let state' = notifyWatches_loop literal (clause # Wl') newWl state in
                  ?Cond1 state' ?state''  ?Cond2 Wl' state' ?state''
                show ?thesis
                  unfolding setReason_def
                  unfolding swapWatches_def
                  by (simp add:Let_def del: notifyWatches_loop.simps)
              next
                case False
                thus ?thesis
                  using (nth (getF state) clause) el (getF state) ‹isUnitClause (nth (getF state) clause) ?w1 (elements (getM state))
                        ?w2 = literal
                        ?w2 el (nth (getF state) clause)
                  by (auto simp add:Let_def)
              qed
            } 
            hence "let state' = notifyWatches_loop literal (clause # Wl') newWl state in
                ?Cond1 state' state"
              by simp
            moreover
            {
              fix c
              assume "c  set (clause # Wl')"
              have "let state' = notifyWatches_loop literal (clause # Wl') newWl state in 
                 l. isUnitClause (nth (getF state) c) l (elements (getM state))  l  set (getQ state')"
              proof (cases "c = clause")
                case True
                {
                  fix l::Literal
                  assume "isUnitClause (nth (getF state) c) l (elements (getM state))"
                  with ‹isUnitClause (nth (getF state) clause) ?w1 (elements (getM state)) c = clause
                  have "l = ?w1"
                    unfolding isUnitClause_def
                    by auto
                  have "isPrefix (getQ ?state'') (getQ (notifyWatches_loop literal Wl' (clause # newWl) ?state''))"
                    using ‹InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')
                    using notifyWatchesLoopPreservedVariables[of "?state''" "Wl'" "literal" "clause # newWl"]
                    using Cons(5)
                    unfolding swapWatches_def
                    unfolding setReason_def
                    by (simp add: Let_def)
                  hence "set (getQ ?state'')  set (getQ (notifyWatches_loop literal Wl' (clause # newWl) ?state''))"
                    using prefixIsSubset[of "getQ ?state''" "getQ (notifyWatches_loop literal Wl' (clause # newWl) ?state'')"]
                    by auto
                  hence "l  set (getQ (notifyWatches_loop literal Wl' (clause # newWl) ?state''))"
                    using l = ?w1
                    unfolding swapWatches_def
                    unfolding setReason_def
                  by auto
              } 
              thus ?thesis
                using ‹notifyWatches_loop literal Wl' (clause # newWl) ?state'' = notifyWatches_loop literal (clause # Wl') newWl state
                by (simp add:Let_def)
            next
                case False
                hence "c  set Wl'"
                  using c  set (clause # Wl')
                  by simp
                {
                  fix l::Literal
                  assume "isUnitClause (nth (getF state) c) l (elements (getM state))"
                  hence "isUnitClause (nth (getF ?state'') c) l (elements (getM ?state''))"
                    unfolding setReason_def
                    unfolding swapWatches_def
                    by simp
                  with let state' = notifyWatches_loop literal (clause # Wl') newWl state in
                    ?Cond1 state' ?state''  ?Cond2 Wl' state' ?state''
                    c  set Wl'
                  have "let state' = notifyWatches_loop literal (clause # Wl') newWl state in l  set (getQ state')"
                    by (simp add:Let_def)
                }
                thus ?thesis
                  by (simp add:Let_def)
              qed
            }
            hence "?Cond2 (clause # Wl') (notifyWatches_loop literal (clause # Wl') newWl state) state"
              by (simp add: Let_def)
            ultimately
            show ?thesis
              by (simp add:Let_def)
          qed
        qed
      qed
    qed
  qed
qed

lemma InvariantUniqQAfterNotifyWatchesLoop:
fixes literal :: Literal and Wl :: "nat list" and newWl :: "nat list" and state :: State 
assumes 
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  " (c::nat). c  set Wl  0  c  c < length (getF state)" and
  "InvariantUniqQ (getQ state)"
shows
  "let state' = notifyWatches_loop literal Wl newWl state in
       InvariantUniqQ (getQ state')
  " 
using assms
proof (induct Wl arbitrary: newWl state)
  case Nil
  thus ?case
    by simp
next
  case (Cons clause Wl')
  from  (c::nat). c  set (clause # Wl')  0  c  c < length (getF state)
  have "0  clause  clause < length (getF state)"
    by auto
  then obtain wa::Literal and wb::Literal
    where "getWatch1 state clause = Some wa" and "getWatch2 state clause = Some wb"
    using Cons
    unfolding InvariantWatchesEl_def
    by auto
  show ?case
  proof (cases "Some literal = getWatch1 state clause")
    case True
    let ?state' = "swapWatches clause state"
    let ?w1 = wb
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch2 state clause = Some wb
      unfolding swapWatches_def
      by auto
    let ?w2 = wa
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch1 state clause = Some wa
      unfolding swapWatches_def
      by auto    
    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True
      
      from Cons(2)
      have "InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
        unfolding InvariantWatchesEl_def
        unfolding swapWatches_def
        by auto
      moreover
      have "getM ?state' = getM state  
        getF ?state' = getF state  
        getQ ?state' = getQ state
        "
        unfolding swapWatches_def
        by simp
      ultimately
      show ?thesis
        using Cons(1)[of "?state'" "clause # newWl"]
        using Cons(3) Cons(4)
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹Some literal = getWatch1 state clause
        using ‹literalTrue ?w1 (elements (getM ?state'))
        by (simp add:Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state') clause)"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by simp

        let ?state'' = "setWatch2 clause l' ?state'"

        from Cons(2)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state') clause)
          unfolding InvariantWatchesEl_def
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        moreover
        have "getM ?state'' = getM state 
          getF ?state'' = getF state  
          getQ ?state'' = getQ state"
          unfolding swapWatches_def
          unfolding setWatch2_def
          by simp
        ultimately
        show ?thesis
          using Cons(1)[of "?state''" "newWl"]
          using Cons(3) Cons(4)
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ‹Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using Some
          by (simp add: Let_def)
      next
        case None
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            by auto
          moreover
          have "getM ?state'' = getM state 
          getF ?state'' = getF state  
            getQ ?state'' = getQ state"
            unfolding swapWatches_def
            by simp
          ultimately
          show ?thesis
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(3) Cons(4)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            by (simp add: Let_def)
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"
          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          have "getM ?state'' = getM state"
            "getF ?state'' = getF state"
            "getQ ?state'' = (if ?w1 el (getQ state) then (getQ state) else (getQ state) @ [?w1])"
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          have "uniq (getQ ?state'')"
            using Cons(4)
            using ‹getQ ?state'' = (if ?w1 el (getQ state) then (getQ state) else (getQ state) @ [?w1])
            unfolding InvariantUniqQ_def
            by (simp add: uniqAppendIff)
          ultimately
          show ?thesis
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(3)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            unfolding isPrefix_def
            unfolding InvariantUniqQ_def
            by (simp add: Let_def split: if_split_asm)
        qed
      qed
    qed
  next
    case False
    let ?state' = state
    let ?w1 = wa
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch1 state clause = Some wa
      by auto
    let ?w2 = wb
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch2 state clause = Some wb
      by auto    
    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True
      thus ?thesis
        using Cons
        using ¬ Some literal = getWatch1 state clause
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹literalTrue ?w1 (elements (getM ?state'))
        by (simp add:Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state')) clause"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by simp

        let ?state'' = "setWatch2 clause l' ?state'"

        from Cons(2)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state')) clause
          unfolding InvariantWatchesEl_def
          unfolding setWatch2_def
          by auto
        moreover
        have "getM ?state'' = getM state 
          getF ?state'' = getF state  
          getQ ?state'' = getQ state"
          unfolding setWatch2_def
          by simp
        ultimately
        show ?thesis
          using Cons(1)[of "?state''"]
          using Cons(3) Cons(4)
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ¬ Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using Some
          by (simp add: Let_def)
      next
        case None
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            by auto
          moreover
          have "getM ?state'' = getM state 
            getF ?state'' = getF state  
            getQ ?state'' = getQ state"
            by simp
          ultimately
          show ?thesis
            using Cons(1)[of "?state''"]
            using Cons(3) Cons(4)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ¬ Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            by (simp add: Let_def)
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"
          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding setReason_def
            by auto
          moreover
          have "getM ?state'' = getM state"
            "getF ?state'' = getF state"
            "getQ ?state'' = (if ?w1 el (getQ state) then (getQ state) else (getQ state) @ [?w1])"
            unfolding setReason_def
            by auto
          moreover
          have "uniq (getQ ?state'')"
            using Cons(4)
            using ‹getQ ?state'' = (if ?w1 el (getQ state) then (getQ state) else (getQ state) @ [?w1])
            unfolding InvariantUniqQ_def
            by (simp add: uniqAppendIff)
          ultimately
          show ?thesis
            using Cons(1)[of "?state''"]
            using Cons(3)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ¬ Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            unfolding isPrefix_def
            unfolding InvariantUniqQ_def
            by (simp add: Let_def split: if_split_asm)
        qed
      qed
    qed
  qed
qed

lemma InvariantConflictClauseCharacterizationAfterNotifyWatches:
assumes 
  "(getM state) = M @ [(opposite literal, decision)]" and
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  " (c::nat). c  set Wl  0  c  c < length (getF state)" and
  " (c::nat). c  set Wl  Some literal = (getWatch1 state c)   Some literal = (getWatch2 state c)" and
  "InvariantConflictClauseCharacterization (getConflictFlag state) (getConflictClause state) (getF state) (getM state)"
  "uniq Wl"
shows 
  "let state' = (notifyWatches_loop literal Wl newWl state) in
   InvariantConflictClauseCharacterization (getConflictFlag state') (getConflictClause state') (getF state') (getM state')"
using assms
proof (induct Wl arbitrary: newWl state)
  case Nil
  thus ?case
    by simp
next
  case (Cons clause Wl')

  from ‹uniq (clause # Wl')
  have "clause  set Wl'" "uniq Wl'"
    by (auto simp add:uniqAppendIff)

  from  (c::nat). c  set (clause # Wl')  0  c  c < length (getF state)
  have "0  clause  clause < length (getF state)"
    by auto
  then obtain wa::Literal and wb::Literal
    where "getWatch1 state clause = Some wa" and "getWatch2 state clause = Some wb"
    using Cons
    unfolding InvariantWatchesEl_def
    by auto
  show ?case
  proof (cases "Some literal = getWatch1 state clause")
    case True
    let ?state' = "swapWatches clause state"
    let ?w1 = wb
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch2 state clause = Some wb
      unfolding swapWatches_def
      by auto
    let ?w2 = wa
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch1 state clause = Some wa
      unfolding swapWatches_def
      by auto

    with True have
      "?w2 = literal"
      unfolding swapWatches_def
      by simp
    hence "literalFalse ?w2 (elements (getM state))"
      using Cons(2)
      by simp

    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True
      
      from Cons(3)
      have "InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
        unfolding InvariantWatchesEl_def
        unfolding swapWatches_def
        by auto
      moreover
      have "c. c  set Wl'  Some literal = getWatch1 ?state' c  Some literal = getWatch2 ?state' c"
        using Cons(5)
        unfolding swapWatches_def
        by auto
      moreover
      have "getM ?state' = getM state  
        getF ?state' = getF state  
        getConflictFlag ?state' = getConflictFlag state  
        getConflictClause ?state' = getConflictClause state
        "
        unfolding swapWatches_def
        by simp
      ultimately
      show ?thesis
        using Cons(1)[of "?state'" "clause # newWl"]
        using Cons(2) Cons(4) Cons(6) Cons(7)
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹Some literal = getWatch1 state clause
        using ‹literalTrue ?w1 (elements (getM ?state'))
        using ‹uniq Wl'
        by (simp add:Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state') clause)"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by simp

        let ?state'' = "setWatch2 clause l' ?state'"

        from Cons(3)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state') clause)
          unfolding InvariantWatchesEl_def
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        moreover
        have "  (c::nat). c  set Wl'  Some literal = (getWatch1 ?state'' c)   Some literal = (getWatch2 ?state'' c)"
          using Cons(5)
          using clause  set Wl'
          using swapWatchesEffect[of "clause" "state"]
          unfolding setWatch2_def
          by simp
        moreover
        have "getM ?state'' = getM state 
          getF ?state'' = getF state  
          getConflictFlag ?state'' = getConflictFlag state  
          getConflictClause ?state'' = getConflictClause state"
          unfolding swapWatches_def
          unfolding setWatch2_def
          by simp
        ultimately
        show ?thesis
          using Cons(1)[of "?state''" "newWl"]
          using Cons(2) Cons(4) Cons(6) Cons(7)
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ‹Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using Some
          using ‹uniq Wl'
          by (simp add: Let_def)
      next
        case None
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons(3)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            by auto
          moreover
          have "getM ?state'' = getM state 
            getF ?state'' = getF state  
            getConflictFlag ?state''  
            getConflictClause ?state'' = clause"
            unfolding swapWatches_def
            by simp
          moreover
          have "  (c::nat). c  set Wl'  Some literal = (getWatch1 ?state'' c)   Some literal = (getWatch2 ?state'' c)"
            using Cons(5)
            using clause  set Wl'
            using swapWatchesEffect[of "clause" "state"]
            by simp
          moreover
          have " l. l el (nth (getF ?state'') clause)  l  ?w1  l  ?w2  literalFalse l (elements (getM ?state''))"
            using None
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using getNonWatchedUnfalsifiedLiteralNoneCharacterization[of "nth (getF ?state') clause" "?w1" "?w2" "getM ?state'"]
            unfolding setReason_def
            unfolding swapWatches_def
            by auto

          hence "clauseFalse (nth (getF state) clause) (elements (getM state))"
            using ‹literalFalse ?w1 (elements (getM ?state'))
            using ‹literalFalse ?w2 (elements (getM state))
            unfolding swapWatches_def
            by (auto simp add: clauseFalseIffAllLiteralsAreFalse)
          moreover
          have "(nth (getF state) clause) el (getF state)"
            using 0  clause  clause < length (getF state)
            using nth_mem[of "clause" "getF state"]
            by simp
          ultimately
          show ?thesis
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(2) Cons(4) Cons(6) Cons(7)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            using ‹uniq Wl'
            using 0  clause  clause < length (getF state)
            unfolding InvariantConflictClauseCharacterization_def
            by (simp add: Let_def)
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"
          from Cons(3)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          have "getM ?state'' = getM state"
            "getF ?state'' = getF state"
            "getConflictFlag ?state'' = getConflictFlag state"
            "getConflictClause ?state'' = getConflictClause state"
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          have "  (c::nat). c  set Wl'  Some literal = (getWatch1 ?state'' c)   Some literal = (getWatch2 ?state'' c)"
            using Cons(5)
            using clause  set Wl'
            using swapWatchesEffect[of "clause" "state"]
            unfolding setReason_def
            by simp
          ultimately
          show ?thesis
            using Cons(1)[of "?state''" "clause # newWl"]
            using Cons(2) Cons(4) Cons(6) Cons(7)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            using ‹uniq Wl'
            by (simp add: Let_def)
        qed
      qed
    qed
  next
    case False
    let ?state' = state
    let ?w1 = wa
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch1 state clause = Some wa
      by auto
    let ?w2 = wb
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch2 state clause = Some wb
      by auto

    from ¬ Some literal = getWatch1 state clause
       (c::nat). c  set (clause # Wl')  Some literal = (getWatch1 state c)   Some literal = (getWatch2 state c)
    have "Some literal = getWatch2 state clause"
      by auto
    hence "?w2 = literal"
      using ‹getWatch2 ?state' clause = Some ?w2
      by simp
    hence "literalFalse ?w2 (elements (getM state))"
      using Cons(2)
      by simp

    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True
      thus ?thesis
        using Cons(1)[of "?state'" "clause # newWl"]
        using Cons(2) Cons(3) Cons(4) Cons(5) Cons(6) Cons(7)
        using ¬ Some literal = getWatch1 state clause
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹literalTrue ?w1 (elements (getM ?state'))
        using ‹uniq Wl'
        by (simp add:Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state')) clause"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by simp

        let ?state'' = "setWatch2 clause l' ?state'"

        from Cons(3)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state')) clause
          unfolding InvariantWatchesEl_def
          unfolding setWatch2_def
          by auto
        moreover
        have "getM ?state'' = getM state 
          getF ?state'' = getF state  
          getQ ?state'' = getQ state  
          getConflictFlag ?state'' = getConflictFlag state  
          getConflictClause ?state'' = getConflictClause state"
          unfolding setWatch2_def
          by simp
        moreover
        have "  (c::nat). c  set Wl'  Some literal = (getWatch1 ?state'' c)   Some literal = (getWatch2 ?state'' c)"
          using Cons(5)
          using clause  set Wl'
          unfolding setWatch2_def
          by simp
        ultimately
        show ?thesis
          using Cons(1)[of "?state''" "newWl"]
          using Cons(2) Cons(4) Cons(6) Cons(7)
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ¬ Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using Some
          using ‹uniq Wl'
          by (simp add: Let_def)
      next
        case None
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons(3)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            by auto
          moreover
          have "getM ?state'' = getM state 
            getF ?state'' = getF state  
            getQ ?state'' = getQ state  
            getConflictFlag ?state''  
            getConflictClause ?state'' = clause"
            by simp
          moreover
          have "  (c::nat). c  set Wl'  Some literal = (getWatch1 ?state'' c)   Some literal = (getWatch2 ?state'' c)"
            using Cons(5)
            using clause  set Wl'
            by simp
          moreover
          have " l. l el (nth (getF ?state'') clause)  l  ?w1  l  ?w2  literalFalse l (elements (getM ?state''))"
            using None
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using getNonWatchedUnfalsifiedLiteralNoneCharacterization[of "nth (getF ?state') clause" "?w1" "?w2" "getM ?state'"]
            unfolding setReason_def
            by auto
          hence "clauseFalse (nth (getF state) clause) (elements (getM state))"
            using ‹literalFalse ?w1 (elements (getM ?state'))
            using ‹literalFalse ?w2 (elements (getM state))
            by (auto simp add: clauseFalseIffAllLiteralsAreFalse)
          moreover
          have "(nth (getF state) clause) el (getF state)"
            using 0  clause  clause < length (getF state)
            using nth_mem[of "clause" "getF state"]
            by simp
          ultimately
          show ?thesis
            using Cons(1)[of "?state''"]
            using Cons(2) Cons(4) Cons(6) Cons(7)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ¬ Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            using ‹uniq Wl'
            using 0  clause  clause < length (getF state)
            unfolding InvariantConflictClauseCharacterization_def
            by (simp add: Let_def)
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"
          from Cons(3)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding setReason_def
            by auto
          moreover
          have "getM ?state'' = getM state"
            "getF ?state'' = getF state"
            "getConflictFlag ?state'' = getConflictFlag state"
            "getConflictClause ?state'' = getConflictClause state"
            unfolding setReason_def
            by auto
          moreover
          have "  (c::nat). c  set Wl'  Some literal = (getWatch1 ?state'' c)   Some literal = (getWatch2 ?state'' c)"
            using Cons(5)
            using clause  set Wl'
            unfolding setReason_def
            by simp
          ultimately
          show ?thesis
            using Cons(1)[of "?state''"]
            using Cons(2) Cons(4) Cons(6) Cons(7)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ¬ Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            using ‹uniq Wl'
            by (simp add: Let_def)
        qed
      qed
    qed
  qed
qed

lemma InvariantGetReasonIsReasonQSubset:
  assumes "Q  Q'" and
  "InvariantGetReasonIsReason GetReason F M Q'"
  shows
  "InvariantGetReasonIsReason GetReason F M Q"
using assms
unfolding InvariantGetReasonIsReason_def
by auto

lemma InvariantGetReasonIsReasonAfterNotifyWatches:
assumes 
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  " (c::nat). c  set Wl  0  c  c < length (getF state)" and
  " (c::nat). c  set Wl  Some literal = (getWatch1 state c)   Some literal = (getWatch2 state c)" and
  "uniq Wl"
  "getM state = M @ [(opposite literal, decision)]"
  "InvariantGetReasonIsReason (getReason state) (getF state) (getM state) Q"
shows
  "let state' = notifyWatches_loop literal Wl newWl state in
   let Q' = Q  (set (getQ state') - set (getQ state)) in
     InvariantGetReasonIsReason (getReason state') (getF state') (getM state') Q'"
using assms
proof (induct Wl arbitrary: newWl state Q)
  case Nil
  thus ?case
    by simp
next
  case (Cons clause Wl')

  from ‹uniq (clause # Wl')
  have "clause  set Wl'" "uniq Wl'"
    by (auto simp add:uniqAppendIff)

  from  (c::nat). c  set (clause # Wl')  0  c  c < length (getF state)
  have "0  clause  clause < length (getF state)"
    by auto
  then obtain wa::Literal and wb::Literal
    where "getWatch1 state clause = Some wa" and "getWatch2 state clause = Some wb"
    using Cons
    unfolding InvariantWatchesEl_def
    by auto
  show ?case
  proof (cases "Some literal = getWatch1 state clause")
    case True
    let ?state' = "swapWatches clause state"
    let ?w1 = wb
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch2 state clause = Some wb
      unfolding swapWatches_def
      by auto
    let ?w2 = wa
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch1 state clause = Some wa
      unfolding swapWatches_def
      by auto
    with True have
      "?w2 = literal"
      unfolding swapWatches_def
      by simp
    hence "literalFalse ?w2 (elements (getM state))"
      using Cons(6)
      by simp

    from ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)
    have "?w1 el (nth (getF state) clause)" "?w2 el (nth (getF state) clause)"
      using ‹getWatch1 ?state' clause = Some ?w1
      using ‹getWatch2 ?state' clause = Some ?w2
      using 0  clause  clause < length (getF state)
      unfolding InvariantWatchesEl_def
      unfolding swapWatches_def
      by auto

    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True
      
      from Cons(2)
      have "InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
        unfolding InvariantWatchesEl_def
        unfolding swapWatches_def
        by auto 
      moreover
      have "c. c  set Wl'  Some literal = getWatch1 ?state' c  Some literal = getWatch2 ?state' c"
        using Cons(4)
        unfolding swapWatches_def
        by auto
      moreover
      have "getM ?state' = getM state  
        getF ?state' = getF state  
        getQ ?state' = getQ state  
        getReason ?state' = getReason state
        "
        unfolding swapWatches_def
        by simp
      ultimately
      show ?thesis
        using Cons(1)[of "?state'" "Q" "clause # newWl"]
        using Cons(3) Cons(6) Cons(7)
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹Some literal = getWatch1 state clause
        using ‹literalTrue ?w1 (elements (getM ?state'))
        using ‹uniq Wl'
        by (simp add:Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state') clause)"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by simp

        let ?state'' = "setWatch2 clause l' ?state'"

        from Cons(2)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state') clause)
          unfolding InvariantWatchesEl_def
          unfolding swapWatches_def
          unfolding setWatch2_def
          by auto
        moreover
        have "  (c::nat). c  set Wl'  Some literal = (getWatch1 ?state'' c)   Some literal = (getWatch2 ?state'' c)"
          using Cons(4)
          using clause  set Wl'
          using swapWatchesEffect[of "clause" "state"]
          unfolding setWatch2_def
          by simp
        moreover
        have "getM ?state'' = getM state 
          getF ?state'' = getF state  
          getQ ?state'' = getQ state  
          getReason ?state'' = getReason state"
          unfolding swapWatches_def
          unfolding setWatch2_def
          by simp
        ultimately
        show ?thesis
          using Cons(1)[of "?state''" "Q" "newWl"]
          using Cons(3) Cons(6) Cons(7)
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ‹Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using Some
          using ‹uniq Wl'
          by (simp add: Let_def)
      next
        case None
        hence " l. l el (nth (getF ?state') clause)  l  ?w1  l  ?w2  literalFalse l (elements (getM ?state'))"
          using getNonWatchedUnfalsifiedLiteralNoneCharacterization
          by simp
        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            by auto
          moreover
          have "c. c  set Wl'  Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c"
            using Cons(4)
            unfolding swapWatches_def
            by auto
          moreover
          have "getM ?state'' = getM state 
            getF ?state'' = getF state  
            getQ ?state'' = getQ state  
            getReason ?state'' = getReason state"
            unfolding swapWatches_def
            by simp
          ultimately
          show ?thesis
            using Cons(1)[of "?state''" "Q""clause # newWl"]
            using Cons(3) Cons(6) Cons(7)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            using ‹uniq Wl'
            by (simp add: Let_def)
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"
          let ?state0 = "notifyWatches_loop literal Wl' (clause # newWl) ?state''"


          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          have "getM ?state'' = getM state"
            "getF ?state'' = getF state"
            "getQ ?state'' = (if ?w1 el (getQ state) then (getQ state) else (getQ state) @ [?w1])"
            "getReason ?state'' = (getReason state)(?w1 := Some clause)"
            unfolding swapWatches_def
            unfolding setReason_def
            by auto
          moreover
          hence "  (c::nat). c  set Wl'  Some literal = (getWatch1 ?state'' c)   Some literal = (getWatch2 ?state'' c)"
            using Cons(4)
            using clause  set Wl'
            using swapWatchesEffect[of "clause" "state"]
            unfolding setReason_def
            by simp
          moreover
          have "isUnitClause (nth (getF state) clause) ?w1 (elements (getM state))"
            using  l. l el (nth (getF ?state') clause)  l  ?w1  l  ?w2  literalFalse l (elements (getM ?state'))
            using ?w1 el (nth (getF state) clause)
            using ?w2 el (nth (getF state) clause)
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            using ‹literalFalse ?w2 (elements (getM state))
            unfolding swapWatches_def
            unfolding isUnitClause_def
            by auto
          hence "InvariantGetReasonIsReason (getReason ?state'') (getF ?state'') (getM ?state'') (Q  {?w1})"
            using Cons(7)
            using ‹getM ?state'' = getM state
            using ‹getF ?state'' = getF state
            using ‹getQ ?state'' = (if ?w1 el (getQ state) then (getQ state) else (getQ state) @ [?w1])
            using ‹getReason ?state'' = (getReason state)(?w1 := Some clause)
            using 0  clause  clause < length (getF state)
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using ‹isUnitClause (nth (getF state) clause) ?w1 (elements (getM state))
            unfolding swapWatches_def
            unfolding InvariantGetReasonIsReason_def
            by auto
          moreover
          have "(λa. if a = ?w1 then Some clause else getReason state a) = getReason ?state''"
            unfolding setReason_def
            unfolding swapWatches_def
            by (auto simp add: fun_upd_def)
          ultimately
          have "InvariantGetReasonIsReason (getReason ?state0) (getF ?state0) (getM ?state0) 
                  (Q  (set (getQ ?state0) - set (getQ ?state''))  {?w1})"
            using Cons(1)[of "?state''" "Q  {?w1}" "clause # newWl"]
            using Cons(3) Cons(6) Cons(7)
            using ‹uniq Wl'
            by (simp add: Let_def split: if_split_asm)
          moreover
          have "(Q  (set (getQ ?state0) - set (getQ state)))  (Q  (set (getQ ?state0) - set (getQ ?state''))  {?w1})"
            using ‹getQ ?state'' = (if ?w1 el (getQ state) then (getQ state) else (getQ state) @ [?w1])
            unfolding swapWatches_def
            by auto
          ultimately
          have "InvariantGetReasonIsReason (getReason ?state0) (getF ?state0) (getM ?state0) 
                  (Q  (set (getQ ?state0) - set (getQ state)))"
            using InvariantGetReasonIsReasonQSubset[of "Q  (set (getQ ?state0) - set (getQ state))" 
              "Q  (set (getQ ?state0) - set (getQ ?state''))  {?w1}" "getReason ?state0" "getF ?state0" "getM ?state0"]
            by simp
          moreover
          have "notifyWatches_loop literal (clause # Wl') newWl state = ?state0"
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ‹Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            using ‹uniq Wl'
            by (simp add: Let_def)
          ultimately
          show ?thesis
            by simp
        qed
      qed
    qed
  next
    case False
    let ?state' = state
    let ?w1 = wa
    have "getWatch1 ?state' clause = Some ?w1"
      using ‹getWatch1 state clause = Some wa
      by auto
    let ?w2 = wb
    have "getWatch2 ?state' clause = Some ?w2"
      using ‹getWatch2 state clause = Some wb
      by auto

    have "?w2 = literal"
      using 0  clause  clause < length (getF state)
      using ‹getWatch1 ?state' clause = Some ?w1
      using ‹getWatch2 ?state' clause = Some ?w2
      using Cons(4)
      using False
      by simp

    hence "literalFalse ?w2 (elements (getM state))"
      using Cons(6)
      by simp

    from ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)
    have "?w1 el (nth (getF state) clause)" "?w2 el (nth (getF state) clause)"
      using ‹getWatch1 ?state' clause = Some ?w1
      using ‹getWatch2 ?state' clause = Some ?w2
      using 0  clause  clause < length (getF state)
      unfolding InvariantWatchesEl_def
      unfolding swapWatches_def
      by auto

    show ?thesis
    proof (cases "literalTrue ?w1 (elements (getM ?state'))")
      case True
      thus ?thesis
        using Cons(1)[of "state" "Q" "clause # newWl"]
        using Cons(2) Cons(3) Cons(4) Cons(5) Cons(6) Cons(7)
        using ¬ Some literal = getWatch1 state clause
        using ‹getWatch1 ?state' clause = Some ?w1
        using ‹getWatch2 ?state' clause = Some ?w2
        using ‹literalTrue ?w1 (elements (getM ?state'))
        using ‹uniq Wl'
        by (simp add:Let_def)
    next
      case False
      show ?thesis
      proof (cases "getNonWatchedUnfalsifiedLiteral (nth (getF ?state') clause) ?w1 ?w2 (getM ?state')")
        case (Some l')
        hence "l' el (nth (getF ?state')) clause"
          using getNonWatchedUnfalsifiedLiteralSomeCharacterization
          by simp

        let ?state'' = "setWatch2 clause l' ?state'"

        from Cons(2)
        have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
          using l' el (nth (getF ?state')) clause
          unfolding InvariantWatchesEl_def
          unfolding setWatch2_def
          by auto
        moreover
        have "c. c  set Wl'  Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c"
          using Cons(4)
          using clause  set Wl'
          unfolding setWatch2_def
          by simp
        moreover
        have "getM ?state'' = getM state 
          getF ?state'' = getF state  
          getQ ?state'' = getQ state  
          getReason ?state'' = getReason state"
          unfolding setWatch2_def
          by simp
        ultimately
        show ?thesis
          using Cons(1)[of "?state''"]
          using Cons(3) Cons(6) Cons(7)
          using ‹getWatch1 ?state' clause = Some ?w1
          using ‹getWatch2 ?state' clause = Some ?w2
          using ¬ Some literal = getWatch1 state clause
          using ¬ literalTrue ?w1 (elements (getM ?state'))
          using ‹uniq Wl'
          using Some
          by (simp add: Let_def)
      next
        case None
        hence " l. l el (nth (getF ?state') clause)  l  ?w1  l  ?w2  literalFalse l (elements (getM ?state'))"
          using getNonWatchedUnfalsifiedLiteralNoneCharacterization
          by simp

        show ?thesis
        proof (cases "literalFalse ?w1 (elements (getM ?state'))")
          case True
          let ?state'' = "?state'getConflictFlag := True, getConflictClause := clause"
          
          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            by auto
          moreover
          have "c. c  set Wl'  Some literal = getWatch1 ?state'' c  Some literal = getWatch2 ?state'' c"
            using Cons(4)
            using clause  set Wl'
            unfolding setWatch2_def
            by simp
          moreover
          have "getM ?state'' = getM state 
            getF ?state'' = getF state  
            getQ ?state'' = getQ state  
            getReason ?state'' = getReason state"
            by simp
          ultimately
          show ?thesis
            using Cons(1)[of "?state''"]
            using Cons(3) Cons(6) Cons(7)
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ¬ Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ‹literalFalse ?w1 (elements (getM ?state'))
            using ‹uniq Wl'
            by (simp add: Let_def)
        next
          case False
          let ?state'' = "setReason ?w1 clause (?state'getQ := (if ?w1 el (getQ ?state') then (getQ ?state') else (getQ ?state') @ [?w1]))"
          let ?state0 = "notifyWatches_loop literal Wl' (clause # newWl) ?state''"


          from Cons(2)
          have "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
            unfolding InvariantWatchesEl_def
            unfolding setReason_def
            by auto
          moreover
          have "getM ?state'' = getM state"
            "getF ?state'' = getF state"
            "getQ ?state'' = (if ?w1 el (getQ state) then (getQ state) else (getQ state) @ [?w1])"
            "getReason ?state'' = (getReason state)(?w1 := Some clause)"
            unfolding setReason_def
            by auto
          moreover
          hence "  (c::nat). c  set Wl'  Some literal = (getWatch1 ?state'' c)   Some literal = (getWatch2 ?state'' c)"
            using Cons(4)
            using clause  set Wl'
            unfolding setReason_def
            by simp
          moreover
          have "isUnitClause (nth (getF state) clause) ?w1 (elements (getM state))"
            using  l. l el (nth (getF ?state') clause)  l  ?w1  l  ?w2  literalFalse l (elements (getM ?state'))
            using ?w1 el (nth (getF state) clause)
            using ?w2 el (nth (getF state) clause)
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            using ‹literalFalse ?w2 (elements (getM state))
            unfolding isUnitClause_def
            by auto
          hence "InvariantGetReasonIsReason (getReason ?state'') (getF ?state'') (getM ?state'') (Q  {?w1})"
            using Cons(7)
            using ‹getM ?state'' = getM state
            using ‹getF ?state'' = getF state
            using ‹getQ ?state'' = (if ?w1 el (getQ state) then (getQ state) else (getQ state) @ [?w1])
            using ‹getReason ?state'' = (getReason state)(?w1 := Some clause)
            using 0  clause  clause < length (getF state)
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using ‹isUnitClause (nth (getF state) clause) ?w1 (elements (getM state))
            unfolding InvariantGetReasonIsReason_def
            by auto
          moreover
          have "(λa. if a = ?w1 then Some clause else getReason state a) = getReason ?state''"
            unfolding setReason_def
            by (auto simp add: fun_upd_def)
          ultimately
          have "InvariantGetReasonIsReason (getReason ?state0) (getF ?state0) (getM ?state0) 
                  (Q  (set (getQ ?state0) - set (getQ ?state''))  {?w1})"
            using Cons(1)[of "?state''" "Q  {?w1}" "clause # newWl"]
            using Cons(3) Cons(6) Cons(7)
            using ‹uniq Wl'
            by (simp add: Let_def split: if_split_asm)
          moreover
          have "(Q  (set (getQ ?state0) - set (getQ state)))  (Q  (set (getQ ?state0) - set (getQ ?state''))  {?w1})"
            using ‹getQ ?state'' = (if ?w1 el (getQ state) then (getQ state) else (getQ state) @ [?w1])
            by auto
          ultimately
          have "InvariantGetReasonIsReason (getReason ?state0) (getF ?state0) (getM ?state0) 
                  (Q  (set (getQ ?state0) - set (getQ state)))"
            using InvariantGetReasonIsReasonQSubset[of "Q  (set (getQ ?state0) - set (getQ state))" 
              "Q  (set (getQ ?state0) - set (getQ ?state''))  {?w1}" "getReason ?state0" "getF ?state0" "getM ?state0"]
            by simp
          moreover
          have "notifyWatches_loop literal (clause # Wl') newWl state = ?state0"
            using ‹getWatch1 ?state' clause = Some ?w1
            using ‹getWatch2 ?state' clause = Some ?w2
            using ¬ Some literal = getWatch1 state clause
            using ¬ literalTrue ?w1 (elements (getM ?state'))
            using None
            using ¬ literalFalse ?w1 (elements (getM ?state'))
            using ‹uniq Wl'
            by (simp add: Let_def)
          ultimately
          show ?thesis
            by simp
        qed
      qed
    qed
  qed
qed


(****************************************************************************)
(*  A S S E R T   L I T E R A L                                             *)
(****************************************************************************)

lemma assertLiteralEffect:
fixes state::State and l::Literal and d::bool
assumes 
"InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)"
"InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)"
shows
"(getM (assertLiteral l d state)) = (getM state) @ [(l, d)]" and 
"(getF (assertLiteral l d state)) = (getF state)" and
"(getSATFlag (assertLiteral l d state)) = (getSATFlag state)" and
"isPrefix (getQ state) (getQ (assertLiteral l d state))"
using assms
unfolding assertLiteral_def
unfolding notifyWatches_def
unfolding InvariantWatchListsContainOnlyClausesFromF_def
using notifyWatchesLoopPreservedVariables[of "(stategetM := getM state @ [(l, d)])" "getWatchList (stategetM := getM state @ [(l, d)]) (opposite l)"]
by (auto simp add: Let_def)

lemma WatchInvariantsAfterAssertLiteral:
assumes
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)"
shows
  "let state' = (assertLiteral literal decision state) in
     InvariantWatchListsContainOnlyClausesFromF (getWatchList state') (getF state')  
     InvariantWatchListsUniq (getWatchList state')  
     InvariantWatchListsCharacterization (getWatchList state') (getWatch1 state') (getWatch2 state')  
     InvariantWatchesEl (getF state') (getWatch1 state') (getWatch2 state')  
     InvariantWatchesDiffer (getF state') (getWatch1 state') (getWatch2 state')
"
using assms
unfolding assertLiteral_def
unfolding notifyWatches_def
using InvariantWatchesElNotifyWatchesLoop[of "stategetM := getM state @ [(literal, decision)]" "getWatchList state (opposite literal)" "opposite literal" "[]"]
using InvariantWatchesDifferNotifyWatchesLoop[of "stategetM := getM state @ [(literal, decision)]" "getWatchList state (opposite literal)" "opposite literal" "[]"]
using InvariantWatchListsContainOnlyClausesFromFNotifyWatchesLoop[of "stategetM := getM state @ [(literal, decision)]" "getWatchList state (opposite literal)" "[]" "opposite literal"]
using InvariantWatchListsCharacterizationNotifyWatchesLoop[of "stategetM := getM state @ [(literal, decision)]" "(getWatchList (stategetM := getM state @ [(literal, decision)]) (opposite literal))" "opposite literal" "[]"]
unfolding InvariantWatchListsContainOnlyClausesFromF_def
unfolding InvariantWatchListsCharacterization_def
unfolding InvariantWatchListsUniq_def
by (auto simp add: Let_def)


lemma InvariantWatchCharacterizationAfterAssertLiteral:
assumes
  "InvariantConsistent ((getM state) @ [(literal, decision)])" and
  "InvariantUniq ((getM state) @ [(literal, decision)])" and
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"
shows
  "let state' = (assertLiteral literal decision state) in
      InvariantWatchCharacterization (getF state') (getWatch1 state') (getWatch2 state') (getM state')"
proof-
  let ?state = "stategetM := getM state @ [(literal, decision)]"
  let ?state' = "assertLiteral literal decision state"
  have *: "c. c  set (getWatchList ?state (opposite literal)) 
            (w1 w2. Some w1 = getWatch1 ?state' c  Some w2 = getWatch2 ?state' c 
                     watchCharacterizationCondition w1 w2 (getM ?state') (getF ?state' ! c) 
                     watchCharacterizationCondition w2 w1 (getM ?state') (getF ?state' ! c))"
    using assms
    using NotifyWatchesLoopWatchCharacterizationEffect[of "?state" "getM state" "getWatchList ?state (opposite literal)" "opposite literal" "decision" "[]"]
    unfolding InvariantWatchListsContainOnlyClausesFromF_def
    unfolding InvariantWatchListsUniq_def
    unfolding InvariantWatchListsCharacterization_def
    unfolding assertLiteral_def
    unfolding notifyWatches_def
    by (simp add: Let_def)
  {
    fix c
    assume "0  c" and "c < length (getF ?state')"
    fix w1::Literal and w2::Literal
    assume "Some w1 = getWatch1 ?state' c" "Some w2 = getWatch2 ?state' c"
    have "watchCharacterizationCondition w1 w2 (getM ?state') (getF ?state' ! c) 
          watchCharacterizationCondition w2 w1 (getM ?state') (getF ?state' ! c)"
    proof (cases "c  set (getWatchList ?state (opposite literal))")
      case True
      thus ?thesis
        using *
        using ‹Some w1 = getWatch1 ?state' c ‹Some w2 = getWatch2 ?state' c
        by auto
    next
      case False
      hence "Some (opposite literal)  getWatch1 state c" and "Some (opposite literal)  getWatch2 state c"
        using ‹InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)
        unfolding InvariantWatchListsCharacterization_def
        by auto
      moreover
      from assms False
      have "getWatch1 ?state' c = getWatch1 state c" and "getWatch2 ?state' c = getWatch2 state c"
        using notifyWatchesLoopPreservedWatches[of "?state" "getWatchList ?state (opposite literal)" "opposite literal" "[]"]
        using False
        unfolding assertLiteral_def
        unfolding notifyWatches_def
        unfolding InvariantWatchListsContainOnlyClausesFromF_def
        by (auto simp add: Let_def)
      ultimately
      have "w1  opposite literal" "w2  opposite literal"
        using ‹Some w1 = getWatch1 ?state' c and ‹Some w2 = getWatch2 ?state' c
        by auto

      have "watchCharacterizationCondition w1 w2 (getM state) (getF state ! c)" and
           "watchCharacterizationCondition w2 w1 (getM state) (getF state ! c)"
        using ‹InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)
        using ‹Some w1 = getWatch1 ?state' c and ‹Some w2 = getWatch2 ?state' c
        using ‹getWatch1 ?state' c = getWatch1 state c and ‹getWatch2 ?state' c = getWatch2 state c
        unfolding InvariantWatchCharacterization_def
        using c < length (getF ?state')
        using assms
        using assertLiteralEffect[of "state" "literal" "decision"]
        by auto

      have "watchCharacterizationCondition w1 w2 (getM ?state') ((getF ?state') ! c)"
      proof-
        {
          assume "literalFalse w1 (elements (getM ?state'))"
            with w1  opposite literal
            have "literalFalse w1 (elements (getM state))"
            using assms
            using assertLiteralEffect[of "state" "literal" "decision"]
            by simp
          with ‹watchCharacterizationCondition w1 w2 (getM state) (getF state ! c)
          have "( l. l el ((getF state) ! c)  literalTrue l (elements (getM state))
             elementLevel l (getM state)  elementLevel (opposite w1) (getM state))  
            (l. l el (getF state ! c)  l  w1  l  w2 
            literalFalse l (elements (getM state))  
            elementLevel (opposite l) (getM state)  elementLevel (opposite w1) (getM state))" (is "?a state  ?b state")
            unfolding watchCharacterizationCondition_def
            using assms
            using assertLiteralEffect[of "state" "literal" "decision"]
            using w1  opposite literal
            by simp
          have "?a ?state'  ?b ?state'"
          proof (cases "?b state")
            case True
            show ?thesis
            proof-
              {
                fix l
                assume "l el (nth (getF ?state') c)" "l  w1" "l  w2"
                have "literalFalse l (elements (getM ?state'))  
                      elementLevel (opposite l) (getM ?state')  elementLevel (opposite w1) (getM ?state')"
                proof-
                  from True l el (nth (getF ?state') c) l  w1 l  w2
                  have "literalFalse l (elements (getM state))"
                    "elementLevel (opposite l) (getM state)  elementLevel (opposite w1) (getM state)"
                    using assms 
                    using assertLiteralEffect[of "state" "literal" "decision"]
                    by auto
                  thus ?thesis
                    using ‹literalFalse w1 (elements (getM state))
                    using elementLevelAppend[of "opposite w1" "getM state" "[(literal, decision)]"]
                    using elementLevelAppend[of "opposite l" "getM state" "[(literal, decision)]"]
                    using assms 
                    using assertLiteralEffect[of "state" "literal" "decision"]
                    by auto
                qed
              }
              thus ?thesis
                by simp
            qed
          next
            case False
            with ?a state  ?b state
            obtain l::Literal
              where "l el (getF state ! c)" "literalTrue l (elements (getM state))" 
              "elementLevel l (getM state)  elementLevel (opposite w1) (getM state)"
              by auto
            
            from w1  opposite literal
              ‹literalFalse w1 (elements (getM ?state'))
            have "elementLevel (opposite w1) ((getM state) @ [(literal, decision)]) = elementLevel (opposite w1) (getM state)"
              using assms
              using assertLiteralEffect[of "state" "literal" "decision"]
              unfolding elementLevel_def
              by (simp add: markedElementsToAppend)
            moreover
            from ‹literalTrue l (elements (getM state))
            have "elementLevel l ((getM state) @ [(literal, decision)]) = elementLevel l (getM state)"
              unfolding elementLevel_def
              by (simp add: markedElementsToAppend)
            ultimately
            have "elementLevel l ((getM state) @ [(literal, decision)])  elementLevel (opposite w1) ((getM state) @ [(literal, decision)])"
              using ‹elementLevel l (getM state)  elementLevel (opposite w1) (getM state)
              by simp
            thus ?thesis
              using l el (getF state ! c) ‹literalTrue l (elements (getM state))
              using assms
              using assertLiteralEffect[of "state" "literal" "decision"]
              by auto
          qed
        }
        thus ?thesis
          unfolding watchCharacterizationCondition_def
          by auto
      qed
      moreover
      have "watchCharacterizationCondition w2 w1 (getM ?state') ((getF ?state') ! c)"
      proof-
        {
          assume "literalFalse w2 (elements (getM ?state'))"
            with w2  opposite literal
            have "literalFalse w2 (elements (getM state))"
            using assms
            using assertLiteralEffect[of "state" "literal" "decision"]
            by simp
          with ‹watchCharacterizationCondition w2 w1 (getM state) (getF state ! c)
          have "( l. l el ((getF state) ! c)  literalTrue l (elements (getM state))
             elementLevel l (getM state)  elementLevel (opposite w2) (getM state))  
            (l. l el (getF state ! c)  l  w2  l  w1 
            literalFalse l (elements (getM state))  
            elementLevel (opposite l) (getM state)  elementLevel (opposite w2) (getM state))" (is "?a state  ?b state")
            unfolding watchCharacterizationCondition_def
            using assms
            using assertLiteralEffect[of "state" "literal" "decision"]
            using w2  opposite literal
            by simp
          have "?a ?state'  ?b ?state'"
          proof (cases "?b state")
            case True
            show ?thesis
            proof-
              {
                fix l
                assume "l el (nth (getF ?state') c)" "l  w1" "l  w2"
                have "literalFalse l (elements (getM ?state'))  
                      elementLevel (opposite l) (getM ?state')  elementLevel (opposite w2) (getM ?state')"
                proof-
                  from True l el (nth (getF ?state') c) l  w1 l  w2
                  have "literalFalse l (elements (getM state))"
                    "elementLevel (opposite l) (getM state)  elementLevel (opposite w2) (getM state)"
                    using assms 
                    using assertLiteralEffect[of "state" "literal" "decision"]
                    by auto
                  thus ?thesis
                    using ‹literalFalse w2 (elements (getM state))
                    using elementLevelAppend[of "opposite w2" "getM state" "[(literal, decision)]"]
                    using elementLevelAppend[of "opposite l" "getM state" "[(literal, decision)]"]
                    using assms 
                    using assertLiteralEffect[of "state" "literal" "decision"]
                    by auto
                qed
              }
              thus ?thesis
                by simp
            qed
          next
            case False
            with ?a state  ?b state
            obtain l::Literal
              where "l el (getF state ! c)" "literalTrue l (elements (getM state))" 
              "elementLevel l (getM state)  elementLevel (opposite w2) (getM state)"
              by auto
            
            from w2  opposite literal
              ‹literalFalse w2 (elements (getM ?state'))
            have "elementLevel (opposite w2) ((getM state) @ [(literal, decision)]) = elementLevel (opposite w2) (getM state)"
              using assms
              using assertLiteralEffect[of "state" "literal" "decision"]
              unfolding elementLevel_def
              by (simp add: markedElementsToAppend)
            moreover
            from ‹literalTrue l (elements (getM state))
            have "elementLevel l ((getM state) @ [(literal, decision)]) = elementLevel l (getM state)"
              unfolding elementLevel_def
              by (simp add: markedElementsToAppend)
            ultimately
            have "elementLevel l ((getM state) @ [(literal, decision)])  elementLevel (opposite w2) ((getM state) @ [(literal, decision)])"
              using ‹elementLevel l (getM state)  elementLevel (opposite w2) (getM state)
              by simp
            thus ?thesis
              using l el (getF state ! c) ‹literalTrue l (elements (getM state))
              using assms
              using assertLiteralEffect[of "state" "literal" "decision"]
              by auto
          qed
        }
        thus ?thesis
          unfolding watchCharacterizationCondition_def
          by auto
      qed
      ultimately
      show ?thesis
        by simp
    qed
  }
  thus ?thesis
    unfolding InvariantWatchCharacterization_def
    by (simp add: Let_def)
qed


lemma assertLiteralConflictFlagEffect:
assumes
  "InvariantConsistent ((getM state) @ [(literal, decision)])"
  "InvariantUniq ((getM state) @ [(literal, decision)])"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)"
  "InvariantWatchListsUniq (getWatchList state)"
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"
shows
"let state' = assertLiteral literal decision state in
    getConflictFlag state' = (getConflictFlag state  
                                 ( clause. clause el (getF state)  
                                            opposite literal el clause  
                                            clauseFalse clause ((elements (getM state)) @ [literal])))"
proof-
  let ?state = "stategetM := getM state @ [(literal, decision)]"
  let ?state' = "assertLiteral literal decision state"

  have "getConflictFlag ?state' = (getConflictFlag state  
          ( clause. clause  set (getWatchList ?state (opposite literal))  
                     clauseFalse (nth (getF ?state) clause) (elements (getM ?state))))"
    using NotifyWatchesLoopConflictFlagEffect[of "?state" 
      "getWatchList ?state (opposite literal)"
      "opposite literal" "[]"]
    using ‹InvariantConsistent ((getM state) @ [(literal, decision)])
    using ‹InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)
    using ‹InvariantWatchListsUniq (getWatchList state)
    using ‹InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)
    using ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)
    unfolding InvariantWatchListsUniq_def
    unfolding InvariantWatchListsCharacterization_def
    unfolding InvariantWatchListsContainOnlyClausesFromF_def
    unfolding assertLiteral_def
    unfolding notifyWatches_def
    by (simp add: Let_def)
  moreover
  have "( clause. clause  set (getWatchList ?state (opposite literal))  
                     clauseFalse (nth (getF ?state) clause) (elements (getM ?state))) = 
        ( clause. clause el (getF state)  
                     opposite literal el clause  
                     clauseFalse clause ((elements (getM state)) @ [literal]))" (is "?lhs = ?rhs")
  proof
    assume "?lhs"
    then obtain clause
      where "clause  set (getWatchList ?state (opposite literal))" 
      "clauseFalse (nth (getF ?state) clause) (elements (getM ?state))"
      by auto

    have "getWatch1 ?state clause = Some (opposite literal)  getWatch2 ?state clause = Some (opposite literal)"
      "clause < length (getF ?state)"
      " w1 w2. getWatch1 ?state clause = Some w1  getWatch2 ?state clause = Some w2  
      w1 el (nth (getF ?state) clause)  w2 el (nth (getF ?state) clause)"
      using clause  set (getWatchList ?state (opposite literal))
      using assms
      unfolding InvariantWatchListsContainOnlyClausesFromF_def
      unfolding InvariantWatchesEl_def
      unfolding InvariantWatchListsCharacterization_def
      by auto
    hence "(nth (getF ?state) clause) el (getF ?state)"
      "opposite literal el (nth (getF ?state) clause)"
      using nth_mem[of "clause" "getF ?state"]
      by auto
    thus "?rhs"
      using ‹clauseFalse (nth (getF ?state) clause) (elements (getM ?state))
      by auto
  next
    assume "?rhs"
    then obtain clause
      where "clause el (getF ?state)" 
      "opposite literal el clause"
      "clauseFalse clause ((elements (getM state)) @ [literal])"
      by auto
    then obtain ci
      where "clause = (nth (getF ?state) ci)" "ci < length (getF ?state)"
      by (auto simp add: in_set_conv_nth)
    moreover
    from ci < length (getF ?state)
    obtain w1 w2
      where "getWatch1 state ci = Some w1" "getWatch2 state ci = Some w2" 
      "w1 el (nth (getF state) ci)" "w2 el (nth (getF state) ci)"
      using assms
      unfolding InvariantWatchesEl_def
      by auto
    have " getWatch1 state ci = Some (opposite literal)  getWatch2 state ci = Some (opposite literal)"
    proof-
      {
        assume "¬ ?thesis"
        with ‹clauseFalse clause ((elements (getM state)) @ [literal])
          clause = (nth (getF ?state) ci)
          ‹getWatch1 state ci = Some w1 ‹getWatch2 state ci = Some w2
          w1 el (nth (getF state) ci) w2 el (nth (getF state) ci)
        have "literalFalse w1 (elements (getM state))" "literalFalse w2 (elements (getM state))"
          by (auto simp add: clauseFalseIffAllLiteralsAreFalse)
        

        
        from ‹InvariantConsistent ((getM state) @ [(literal, decision)])
        ‹clauseFalse clause ((elements (getM state)) @ [literal])
        have "¬ ( l. l el clause  literalTrue l (elements (getM state)))"
          unfolding InvariantConsistent_def
          by (auto simp add: inconsistentCharacterization clauseFalseIffAllLiteralsAreFalse)


        from ‹InvariantUniq ((getM state) @ [(literal, decision)])
        have "¬ literalTrue literal (elements (getM state))"
          unfolding InvariantUniq_def
          by (auto simp add: uniqAppendIff)
        
        from ‹InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)
          ‹literalFalse w1 (elements (getM state)) ‹literalFalse w2 (elements (getM state))
          ¬ ( l. l el clause  literalTrue l (elements (getM state)))
          ‹getWatch1 state ci = Some w1[THEN sym] 
          ‹getWatch2 state ci = Some w2[THEN sym]
          ci < length (getF ?state)
          clause = (nth (getF ?state) ci)
        have " l. l el clause  l  w1  l  w2  literalFalse l (elements (getM state))"
          unfolding InvariantWatchCharacterization_def
          unfolding watchCharacterizationCondition_def
          by auto
        hence "literalTrue literal (elements (getM state))"
          using ¬ (getWatch1 state ci = Some (opposite literal)  getWatch2 state ci = Some (opposite literal))
          using ‹opposite literal el clause
          using ‹getWatch1 state ci = Some w1
          using ‹getWatch2 state ci = Some w2
          by auto
        with ¬ literalTrue literal (elements (getM state))
        have False
          by simp
      }
      thus ?thesis
        by auto
    qed
    ultimately
    show "?lhs"
      using assms
      using ‹clauseFalse clause ((elements (getM state)) @ [literal])
      unfolding InvariantWatchListsCharacterization_def
      by force
  qed
  ultimately
  show ?thesis
    by auto
qed

lemma InvariantConflictFlagCharacterizationAfterAssertLiteral:
assumes
  "InvariantConsistent ((getM state) @ [(literal, decision)])"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)"
shows
  "let state' = (assertLiteral literal decision state) in
      InvariantConflictFlagCharacterization (getConflictFlag state') (getF state') (getM state')"
proof-
  let ?state = "stategetM := getM state @ [(literal, decision)]"
  let ?state' = "assertLiteral literal decision state"

  have *:"getConflictFlag ?state' = (getConflictFlag state  
          ( clause. clause  set (getWatchList ?state (opposite literal))  
                     clauseFalse (nth (getF ?state) clause) (elements (getM ?state))))"
    using NotifyWatchesLoopConflictFlagEffect[of "?state" 
      "getWatchList ?state (opposite literal)"
      "opposite literal" "[]"]
    using ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)
    using ‹InvariantConsistent ((getM state) @ [(literal, decision)])
    using ‹InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)
    using ‹InvariantWatchListsUniq (getWatchList state)
    using ‹InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)
    unfolding InvariantWatchListsUniq_def
    unfolding InvariantWatchListsCharacterization_def
    unfolding InvariantWatchListsContainOnlyClausesFromF_def
    unfolding assertLiteral_def
    unfolding notifyWatches_def
    by (simp add: Let_def)

  hence "getConflictFlag state  getConflictFlag ?state'"
    by simp

  show ?thesis
  proof (cases "getConflictFlag state")
    case True
    thus ?thesis
      using ‹InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)
      using assertLiteralEffect[of "state" "literal" "decision"]
      using ‹getConflictFlag state  getConflictFlag ?state'
      using assms
      unfolding InvariantConflictFlagCharacterization_def
      by (auto simp add: Let_def formulaFalseAppendValuation)
  next
    case False
    
    hence "¬ formulaFalse (getF state) (elements (getM state))"
      using ‹InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)
      unfolding InvariantConflictFlagCharacterization_def
      by simp

    have **: " clause. clause  set (getWatchList ?state (opposite literal))  
                          0  clause  clause < length (getF ?state)  
                          ¬ clauseFalse (nth (getF ?state) clause) (elements (getM ?state))"
    proof-
      {
        fix clause
        assume "clause  set (getWatchList ?state (opposite literal))" and
          "0  clause  clause < length (getF ?state)"

        from 0  clause  clause < length (getF ?state)
        obtain w1::Literal and w2::Literal
          where "getWatch1 ?state clause = Some w1" and
                "getWatch2 ?state clause = Some w2" and
                "w1 el (nth (getF ?state) clause)" and
                "w2 el (nth (getF ?state) clause)"
          using ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)
          unfolding InvariantWatchesEl_def
          by auto

        have "¬ clauseFalse (nth (getF ?state) clause) (elements (getM ?state))" 
        proof-
          from clause  set (getWatchList ?state (opposite literal))
          have "w1  opposite literal" and
               "w2  opposite literal"
            using ‹InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)
            using ‹getWatch1 ?state clause = Some w1 and ‹getWatch2 ?state clause = Some w2
            unfolding InvariantWatchListsCharacterization_def
            by auto

          from ¬ formulaFalse (getF state) (elements (getM state))
          have "¬ clauseFalse (nth (getF ?state) clause) (elements (getM state))"
            using  0  clause  clause < length (getF ?state)
            by (simp add: formulaFalseIffContainsFalseClause)
        
          
          show ?thesis
          proof (cases "literalFalse w1 (elements (getM state))  literalFalse w2 (elements (getM state))")
            case True
            (* Depends on the watch characterization invariant *)
            with ‹InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)
            have $: "( l. l el (nth (getF state) clause)  literalTrue l (elements (getM state)))  
                  ( l. l el (nth (getF state) clause)  
                         l  w1  l  w2  literalFalse l (elements (getM state)))
              "
              using ‹getWatch1 ?state clause = Some w1[THEN sym]
              using ‹getWatch2 ?state clause = Some w2[THEN sym]
              using 0  clause  clause < length (getF ?state)
              unfolding InvariantWatchCharacterization_def
              unfolding watchCharacterizationCondition_def
              by auto

            thus ?thesis
            proof (cases " l. l el (nth (getF state) clause)  
                            l  w1  l  w2  literalFalse l (elements (getM state))")
              case True
              have "¬ literalFalse w1 (elements (getM state))  ¬ literalFalse w2 (elements (getM state))"
              proof-
                from ¬ clauseFalse (nth (getF ?state) clause) (elements (getM state))
                obtain l::Literal
                  where "l el (nth (getF ?state) clause)" and "¬ literalFalse l (elements (getM state))"
                  by (auto simp add: clauseFalseIffAllLiteralsAreFalse)
                with True
                show ?thesis
                  by auto
              qed
              hence "¬ literalFalse w1 (elements (getM ?state))  ¬ literalFalse w2 (elements (getM ?state))"
                using w1  opposite literal and w2  opposite literal
                by auto
              thus ?thesis
                using w1 el (nth (getF ?state) clause) w2 el (nth (getF ?state) clause)
                by (auto simp add: clauseFalseIffAllLiteralsAreFalse)
            next
              case False
              then obtain l::Literal
              where "l el (nth (getF state) clause)" and "literalTrue l (elements (getM state))"
                using $
                by auto
              thus ?thesis
                using ‹InvariantConsistent ((getM state) @ [(literal, decision)])
                unfolding InvariantConsistent_def
                by (auto simp add: clauseFalseIffAllLiteralsAreFalse inconsistentCharacterization)
            qed
          next
            case False
            thus ?thesis
              using w1 el (nth (getF ?state) clause) and
                w1  opposite literal
              by (auto simp add: clauseFalseIffAllLiteralsAreFalse)
          qed
        qed
      } thus ?thesis
        by simp
    qed

    show ?thesis
    proof (cases "getConflictFlag ?state'")
      case True
      from ¬ getConflictFlag state ‹getConflictFlag ?state'
      obtain clause::nat
        where
        "clause  set (getWatchList ?state (opposite literal))" and
         "clauseFalse (nth (getF ?state) clause) (elements (getM ?state))"
        using *
        by auto
      from ‹InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)
        clause  set (getWatchList ?state (opposite literal))
      have "(nth (getF ?state) clause) el (getF ?state)"
        unfolding InvariantWatchListsContainOnlyClausesFromF_def
        using nth_mem
        by simp
      with ‹clauseFalse (nth (getF ?state) clause) (elements (getM ?state)) 
      have "formulaFalse (getF ?state) (elements (getM ?state))"
        by (auto simp add: Let_def formulaFalseIffContainsFalseClause)  
      thus ?thesis
        using ¬ getConflictFlag state ‹getConflictFlag ?state'
        unfolding InvariantConflictFlagCharacterization_def
        using assms
        using assertLiteralEffect[of "state" "literal" "decision"]
        by (simp add: Let_def)
    next
      case False
      hence " clause::nat. clause  set (getWatchList ?state (opposite literal))  
        ¬ clauseFalse (nth (getF ?state) clause) (elements (getM ?state))"
        using *
        by auto
      with **
      have " clause. 0  clause  clause < length (getF ?state)  
                          ¬ clauseFalse (nth (getF ?state) clause) (elements (getM ?state))"
        by auto
      hence "¬ formulaFalse (getF ?state) (elements (getM ?state))"
        by (auto simp add:set_conv_nth formulaFalseIffContainsFalseClause)
      thus ?thesis
        using ¬ getConflictFlag state ¬ getConflictFlag ?state'
        using assms
        unfolding InvariantConflictFlagCharacterization_def
        by (auto simp add: Let_def assertLiteralEffect)
    qed
  qed
qed

lemma InvariantConflictClauseCharacterizationAfterAssertLiteral:
assumes 
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)"
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchListsUniq (getWatchList state)"
  "InvariantConflictClauseCharacterization (getConflictFlag state) (getConflictClause state) (getF state) (getM state)"
shows 
  "let state' = assertLiteral literal decision state in
   InvariantConflictClauseCharacterization (getConflictFlag state') (getConflictClause state') (getF state') (getM state')"
proof-
  let ?state0 = "state getM := getM state @ [(literal, decision)]"
  show ?thesis
    using assms
    using InvariantConflictClauseCharacterizationAfterNotifyWatches[of "?state0" "getM state" "opposite literal" "decision" 
    "getWatchList ?state0 (opposite literal)" "[]"]
    unfolding assertLiteral_def
    unfolding notifyWatches_def
    unfolding InvariantWatchListsUniq_def
    unfolding InvariantWatchListsContainOnlyClausesFromF_def
    unfolding InvariantWatchListsCharacterization_def
    unfolding InvariantConflictClauseCharacterization_def
    by (simp add: Let_def clauseFalseAppendValuation)
qed

lemma assertLiteralQEffect:
assumes
  "InvariantConsistent ((getM state) @ [(literal, decision)])"
  "InvariantUniq ((getM state) @ [(literal, decision)])"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)"
  "InvariantWatchListsUniq (getWatchList state)"
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"
shows
"let state' = assertLiteral literal decision state in
    set (getQ state') = set (getQ state)  
           { ul. ( uc. uc el (getF state)  
                        opposite literal el uc  
                        isUnitClause uc ul ((elements (getM state)) @ [literal])) }" 
   (is "let state' = assertLiteral literal decision state in
    set (getQ state') = set (getQ state)  ?ulSet")
proof-
    let ?state' = "stategetM := getM state @ [(literal, decision)]"
    let ?state'' = "assertLiteral literal decision state"
    
    have "set (getQ ?state'') - set (getQ state)  ?ulSet"
      unfolding assertLiteral_def
      unfolding notifyWatches_def
      using assms
      using NotifyWatchesLoopQEffect[of "?state'" "getM state" "opposite literal" "decision" "getWatchList ?state' (opposite literal)" "[]"]
      unfolding InvariantWatchListsCharacterization_def
      unfolding InvariantWatchListsUniq_def
      unfolding InvariantWatchListsContainOnlyClausesFromF_def
      using set_conv_nth[of "getF state"]
      by (auto simp add: Let_def)
    moreover
    have "?ulSet  set (getQ ?state'')"
    proof
      fix ul
      assume "ul  ?ulSet"
      then obtain uc
        where "uc el (getF state)" "opposite literal el uc" "isUnitClause uc ul ((elements (getM state)) @ [literal])"
        by auto
      then obtain uci
        where "uc = (nth (getF state) uci)" "uci < length (getF state)"
        using set_conv_nth[of "getF state"]
        by auto
      let ?w1 = "getWatch1 state uci"
      let ?w2 = "getWatch2 state uci"

      have "?w1 = Some (opposite literal)  ?w2 = Some (opposite literal)"
      proof-
        {
          assume "¬ ?thesis"
          
          from ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)
          obtain wl1 wl2
            where "?w1 = Some wl1" "?w2 = Some wl2" "wl1 el (getF state ! uci)" "wl2 el (getF state ! uci)"
            unfolding InvariantWatchesEl_def
            using uci < length (getF state)
            by force

          with ‹InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)
          have "watchCharacterizationCondition wl1 wl2 (getM state) (getF state ! uci)"
               "watchCharacterizationCondition wl2 wl1 (getM state) (getF state ! uci)"
            using uci < length (getF state)
            unfolding InvariantWatchCharacterization_def
            by auto

          from ‹isUnitClause uc ul ((elements (getM state)) @ [literal])
          have "¬ ( l. l el uc  (literalTrue l ((elements (getM state)) @ [literal])))"
            using containsTrueNotUnit
            using ‹InvariantConsistent ((getM state) @ [(literal, decision)])
            unfolding InvariantConsistent_def
            by auto
          
          from ‹InvariantUniq ((getM state) @ [(literal, decision)])
          have "¬ literal el (elements (getM state))"
            unfolding InvariantUniq_def
            by (simp add: uniqAppendIff)
        
          from ¬ ?thesis 
            ?w1 = Some wl1 ?w2 = Some wl2
          have "wl1  opposite literal" "wl2  opposite literal"
            by auto

          from ‹InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)
          have "wl1  wl2"
            using ?w1 = Some wl1 ?w2 = Some wl2
            unfolding InvariantWatchesDiffer_def
            using uci < length (getF state)
            by auto
          
          have "literalFalse wl1 (elements (getM state))  literalFalse wl2 (elements (getM state))"
          proof (cases "ul = wl1")
            case True
            with wl1  wl2
            have "ul  wl2"
              by simp
            with ‹isUnitClause uc ul ((elements (getM state)) @ [literal])
              wl2  opposite literal wl2 el (getF state ! uci)
              uc = (getF state ! uci)
            show ?thesis
              unfolding isUnitClause_def
              by auto
          next
            case False
            with ‹isUnitClause uc ul ((elements (getM state)) @ [literal])
              wl1  opposite literal wl1 el (getF state ! uci)
              uc = (getF state ! uci)
            show ?thesis
              unfolding isUnitClause_def
              by auto
          qed

          with  ‹watchCharacterizationCondition wl1 wl2 (getM state) (getF state ! uci)
            ‹watchCharacterizationCondition wl2 wl1 (getM state) (getF state ! uci)
            ¬ ( l. l el uc  (literalTrue l ((elements (getM state)) @ [literal])))
            uc = (getF state ! uci)
            ?w1 = Some wl1 ?w2 = Some wl2
          have " l. l el uc  l  wl1  l  wl2  literalFalse l (elements (getM state))"
            unfolding watchCharacterizationCondition_def
            by auto
          with wl1  opposite literal wl2  opposite literal ‹opposite literal el uc
          have "literalTrue literal (elements (getM state))"
            by auto
          with ¬ literal el (elements (getM state))
          have False
            by simp
        } thus ?thesis
          by auto
      qed
      with ‹InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)
      have "uci  set (getWatchList state (opposite literal))"
        unfolding InvariantWatchListsCharacterization_def
        by auto

      thus "ul  set (getQ ?state'')"
        using uc el (getF state) 
        using ‹isUnitClause uc ul ((elements (getM state)) @ [literal])
        using uc = (getF state ! uci)
        unfolding assertLiteral_def
        unfolding notifyWatches_def
        using assms
        using NotifyWatchesLoopQEffect[of "?state'" "getM state" "opposite literal" "decision" "getWatchList ?state' (opposite literal)" "[]"]
        unfolding InvariantWatchListsCharacterization_def
        unfolding InvariantWatchListsUniq_def
        unfolding InvariantWatchListsContainOnlyClausesFromF_def
        by (auto simp add: Let_def)
    qed
    moreover
    have "set (getQ state)  set (getQ ?state'')"
      using assms
      using assertLiteralEffect[of "state" "literal" "decision"]
      using prefixIsSubset[of "getQ state" "getQ ?state''"]
      by simp
    ultimately
    show ?thesis
      by (auto simp add: Let_def)
qed


lemma InvariantQCharacterizationAfterAssertLiteral:
assumes
  "InvariantConsistent ((getM state) @ [(literal, decision)])"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)"
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"
shows
  "let state' = (assertLiteral literal decision state) in
      InvariantQCharacterization (getConflictFlag state') (removeAll literal (getQ state')) (getF state') (getM state')"
proof-
  let ?state = "stategetM := getM state @ [(literal, decision)]"
  let ?state' = "assertLiteral literal decision state"

  have *:"l. l  set (getQ ?state') - set (getQ ?state) 
            (clause. clause el (getF ?state)  isUnitClause clause l (elements (getM ?state)))"
    using NotifyWatchesLoopQEffect[of "?state" "getM state" "opposite literal" "decision"   "getWatchList ?state (opposite literal)" "[]"]
    using assms
    unfolding InvariantWatchListsUniq_def
    unfolding InvariantWatchListsCharacterization_def
    unfolding InvariantWatchListsContainOnlyClausesFromF_def
    unfolding InvariantWatchCharacterization_def
    unfolding assertLiteral_def
    unfolding notifyWatches_def
    by (auto simp add: Let_def)

  have **: " clause. clause  set (getWatchList ?state (opposite literal))  
              ( l. (isUnitClause (nth (getF ?state) clause) l (elements (getM ?state)))  
                      l  (set (getQ ?state')))"
    using NotifyWatchesLoopQEffect[of "?state" "getM state" "opposite literal" "decision" "getWatchList ?state (opposite literal)" "[]"]
    using assms
    unfolding InvariantWatchListsUniq_def
    unfolding InvariantWatchListsCharacterization_def
    unfolding InvariantWatchListsContainOnlyClausesFromF_def
    unfolding InvariantWatchCharacterization_def
    unfolding assertLiteral_def
    unfolding notifyWatches_def
    by (simp add: Let_def)

  have "getConflictFlag state  getConflictFlag ?state'"
  proof-
    have "getConflictFlag ?state' = (getConflictFlag state  
            ( clause. clause  set (getWatchList ?state (opposite literal))  
                       clauseFalse (nth (getF ?state) clause) (elements (getM ?state))))"
      using NotifyWatchesLoopConflictFlagEffect[of "?state" 
        "getWatchList ?state (opposite literal)"
        "opposite literal" "[]"]
      using assms
      unfolding InvariantWatchListsUniq_def
      unfolding InvariantWatchListsCharacterization_def
      unfolding InvariantWatchListsContainOnlyClausesFromF_def
      unfolding assertLiteral_def
      unfolding notifyWatches_def
      by (simp add: Let_def)
    thus ?thesis
      by simp
  qed

  {
    assume "¬ getConflictFlag ?state'"
    with ‹getConflictFlag state  getConflictFlag ?state'
    have "¬ getConflictFlag state"
      by simp

    have "l. l el (removeAll literal (getQ ?state')) =
             (c. c el (getF ?state')  isUnitClause c l (elements (getM ?state')))"
    proof
      fix l::Literal
      show "l el (removeAll literal (getQ ?state')) =
             (c. c el (getF ?state')  isUnitClause c l (elements (getM ?state')))"
      proof
        assume "l el (removeAll literal (getQ ?state'))"
        hence "l el (getQ ?state')" "l  literal"
          by auto
        show "c. c el (getF ?state')  isUnitClause c l (elements (getM ?state'))"
        proof (cases "l el (getQ state)")
          case True
        
          from ¬ getConflictFlag state
            ‹InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)
            l el (getQ state)
          obtain c::Clause
            where "c el (getF state)" "isUnitClause c l (elements (getM state))"
            unfolding InvariantQCharacterization_def
            by auto

          show ?thesis
          proof (cases "l  opposite literal")
            case True
            hence "opposite l  literal"
              by auto
            
            from ‹isUnitClause c l (elements (getM state))
              ‹opposite l  literal l  literal
            have "isUnitClause c l ((elements (getM state) @ [literal]))"
              using isUnitClauseAppendValuation[of "c" "l" "elements (getM state)" "literal"]
              by simp
            thus ?thesis
              using assms
              using c el (getF state)
              using assertLiteralEffect[of "state" "literal" "decision"]
              by auto
          next
            case False
            hence "opposite l = literal"
              by simp

            from ‹isUnitClause c l (elements (getM state))
            have "clauseFalse c (elements (getM ?state'))"
              using assms
              using assertLiteralEffect[of "state" "literal" "decision"]
              using unitBecomesFalse[of "c" "l" "elements (getM state)"]
              using ‹opposite l = literal
              by simp
            with c el (getF state)
            have "formulaFalse (getF state) (elements (getM ?state'))"
              by (auto simp add: formulaFalseIffContainsFalseClause)
                
            from assms
            have "InvariantConflictFlagCharacterization (getConflictFlag ?state') (getF ?state') (getM ?state')"
              using InvariantConflictFlagCharacterizationAfterAssertLiteral
              by (simp add: Let_def)
            with ‹formulaFalse (getF state) (elements (getM ?state'))
            have "getConflictFlag ?state'"
              using assms
              using assertLiteralEffect[of "state" "literal" "decision"]
              unfolding InvariantConflictFlagCharacterization_def
              by auto
            with ¬ getConflictFlag ?state'
            show ?thesis
              by simp
          qed
        next
          case False
          then obtain c::Clause
            where "c el (getF ?state')  isUnitClause c l (elements (getM ?state'))"
            using *
            using l el (getQ ?state')
            using assms
            using assertLiteralEffect[of "state" "literal" "decision"]
            by auto
          thus ?thesis
            using formulaEntailsItsClauses[of "c" "getF ?state'"]
            by auto
          qed
      next
        assume "c. c el (getF ?state')  isUnitClause c l (elements (getM ?state'))"
        then obtain c::Clause
          where "c el (getF ?state')" "isUnitClause c l (elements (getM ?state'))"
          by auto
        then obtain ci::nat
          where "0  ci" "ci < length (getF ?state')" "c = (nth (getF ?state') ci)"
          using set_conv_nth[of "getF ?state'"]
          by auto
        then obtain w1::Literal and w2::Literal
          where "getWatch1 state ci = Some w1" and "getWatch2 state ci = Some w2" and 
          "w1 el c" and "w2 el c"
          using ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state) 
          using c = (nth (getF ?state') ci)
          unfolding InvariantWatchesEl_def
          using assms
          using assertLiteralEffect[of "state" "literal" "decision"]
          by auto
        hence "w1  w2"
          using ci < length (getF ?state')
          using ‹InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)
          unfolding InvariantWatchesDiffer_def
          using assms
          using assertLiteralEffect[of "state" "literal" "decision"]
          by auto

        show "l el (removeAll literal (getQ ?state'))"
        proof (cases "isUnitClause c l (elements (getM state))")
          case True
          with ‹InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)
            ¬ getConflictFlag state
            c el (getF ?state') 
          have "l el (getQ state)"
            using assms
            using assertLiteralEffect[of "state" "literal" "decision"]
            unfolding InvariantQCharacterization_def
            by auto
          have "isPrefix (getQ state) (getQ ?state')"
            using assms
            using assertLiteralEffect[of "state" "literal" "decision"]
            by simp
          then obtain Q' 
            where "(getQ state) @ Q' = (getQ ?state')"
            unfolding isPrefix_def
            by auto
          have "l el (getQ ?state')"
            using l el (getQ state)
            (getQ state) @ Q' = (getQ ?state')[THEN sym]
            by simp
          moreover
          have "l  literal"
            using ‹isUnitClause c l (elements (getM ?state'))
            using assms
            using assertLiteralEffect[of "state" "literal" "decision"]
            unfolding isUnitClause_def
            by simp
          ultimately
          show ?thesis
            by auto
        next
          case False
            (* The clause was not unit in M but it became unit in M' *)
          thus ?thesis
          proof (cases "ci  set (getWatchList ?state (opposite literal))")
            case True
            with ** 
              ‹isUnitClause c l (elements (getM ?state'))
              c = (nth (getF ?state') ci)
            have "l  set (getQ ?state')"
              using assms
              using assertLiteralEffect[of "state" "literal" "decision"]
              by simp
            moreover
            have "l  literal"
              using ‹isUnitClause c l (elements (getM ?state'))
              unfolding isUnitClause_def
              using assms
              using assertLiteralEffect[of "state" "literal" "decision"]
              by simp
            ultimately
            show ?thesis
              by simp
          next
            case False
            with ‹InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)
            have "w1  opposite literal" "w2  opposite literal"
              using ‹getWatch1 state ci = Some w1 and ‹getWatch2 state ci = Some w2
              unfolding InvariantWatchListsCharacterization_def
              by auto
            have "literalFalse w1 (elements (getM state))  literalFalse w2 (elements (getM state))"
            proof-
              {
                assume "¬ ?thesis"
                hence "¬ literalFalse w1 (elements (getM ?state'))" "¬ literalFalse w2 (elements (getM ?state'))"
                  using w1  opposite literal and w2  opposite literal
                  using assms
                  using assertLiteralEffect[of "state" "literal" "decision"]
                  by auto
                with w1  w2 w1 el c w2 el c
                have  "¬ isUnitClause c l (elements (getM ?state'))"
                  unfolding isUnitClause_def
                  by auto
              }
              with ‹isUnitClause c l (elements (getM ?state'))
              show ?thesis
                by auto
            qed
                (* Depends on the watch characterization invariant *)
            with ‹InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)
            have $: "( l. l el c  literalTrue l (elements (getM state)))  
                     ( l. l el c  
                         l  w1  l  w2  literalFalse l (elements (getM state)))
              "
              using ci < length (getF ?state')
              using c = (nth (getF ?state') ci)
              using ‹getWatch1 state ci = Some w1[THEN sym] and ‹getWatch2 state ci = Some w2[THEN sym]
              using assms
              using assertLiteralEffect[of "state" "literal" "decision"]
              unfolding InvariantWatchCharacterization_def
              unfolding watchCharacterizationCondition_def
              by auto
            thus ?thesis
            proof(cases " l. l el c  l  w1  l  w2  literalFalse l (elements (getM state))")
              case True
              with ‹isUnitClause c l (elements (getM ?state'))
              have "literalFalse w1 (elements (getM state))  
                      ¬ literalFalse w2 (elements (getM state))  ¬ literalTrue w2 (elements (getM state))  l = w2"
                   "literalFalse w2 (elements (getM state))  
                      ¬ literalFalse w1 (elements (getM state))  ¬ literalTrue w1 (elements (getM state))  l = w1"
                unfolding isUnitClause_def
                using assms
                using assertLiteralEffect[of "state" "literal" "decision"]
                by auto
              
              with ‹literalFalse w1 (elements (getM state))  literalFalse w2 (elements (getM state))
              have "(literalFalse w1 (elements (getM state))  ¬ literalFalse w2 (elements (getM state))  ¬ literalTrue w2 (elements (getM state))  l = w2)  
                    (literalFalse w2 (elements (getM state))  ¬ literalFalse w1 (elements (getM state))  ¬ literalTrue w1 (elements (getM state))  l = w1)"
                by blast
              hence "isUnitClause c l (elements (getM state))"
                using w1 el c w2 el c True
                unfolding isUnitClause_def
                by auto
              thus ?thesis
                using ¬ isUnitClause c l (elements (getM state))
                by simp
            next
              case False
              then obtain l'::Literal where 
                "l' el c" "literalTrue l' (elements (getM state))"
                using $
                by auto
              hence "literalTrue l' (elements (getM ?state'))"
                using assms
                using assertLiteralEffect[of "state" "literal" "decision"]
                by auto
              
              from ‹InvariantConsistent ((getM state) @ [(literal, decision)])
                l' el c ‹literalTrue l' (elements (getM ?state'))
              show ?thesis
                using containsTrueNotUnit[of "l'" "c" "elements (getM ?state')"]
                using ‹isUnitClause c l (elements (getM ?state'))
                using assms
                using assertLiteralEffect[of "state" "literal" "decision"]
                unfolding InvariantConsistent_def
                by auto
            qed
          qed
        qed
      qed
    qed
  }
  thus ?thesis
    unfolding InvariantQCharacterization_def
    by simp
qed

lemma AssertLiteralStartQIreleveant:
fixes literal :: Literal and Wl :: "nat list" and newWl :: "nat list" and state :: State 
assumes 
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)"
shows
  "let state' = (assertLiteral literal decision (state getQ := Q' )) in
   let state'' = (assertLiteral literal decision (state getQ := Q'' )) in
   (getM state') = (getM state'')  
   (getF state') = (getF state'')  
   (getSATFlag state') = (getSATFlag state'')  
   (getConflictFlag state') = (getConflictFlag state'')
  " 
using assms
unfolding assertLiteral_def
unfolding notifyWatches_def
unfolding InvariantWatchListsContainOnlyClausesFromF_def
using notifyWatchesStartQIreleveant[of 
"state getQ := Q', getM := getM state @ [(literal, decision)] "
"getWatchList (stategetM := getM state @ [(literal, decision)]) (opposite literal)" 
"state getQ := Q'', getM := getM state @ [(literal, decision)] " 
"opposite literal" "[]"]
by (simp add: Let_def)

lemma assertedLiteralIsNotUnit:
assumes
  "InvariantConsistent ((getM state) @ [(literal, decision)])"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"
shows
  "let state' = assertLiteral literal decision state in
      ¬ literal  (set (getQ state') - set(getQ state))"
proof-
  {
    let ?state = "stategetM := getM state @ [(literal, decision)]"
    let ?state' = "assertLiteral literal decision state"

    assume "¬ ?thesis"
    
    have *:"l. l  set (getQ ?state') - set (getQ ?state) 
            (clause. clause el (getF ?state)  isUnitClause clause l (elements (getM ?state)))"
      using NotifyWatchesLoopQEffect[of "?state" "getM state" "opposite literal" "decision"   "getWatchList ?state (opposite literal)" "[]"]
      using assms
      unfolding InvariantWatchListsUniq_def
      unfolding InvariantWatchListsCharacterization_def
      unfolding InvariantWatchListsContainOnlyClausesFromF_def
      unfolding InvariantWatchCharacterization_def
      unfolding assertLiteral_def
      unfolding notifyWatches_def
      by (auto simp add: Let_def)
    with ¬ ?thesis
    obtain clause
      where "isUnitClause clause literal (elements (getM ?state))"
      by (auto simp add: Let_def)
    hence "False"
      unfolding isUnitClause_def
      by simp
  }
  thus ?thesis
    by auto
qed

lemma InvariantQCharacterizationAfterAssertLiteralNotInQ:
assumes
  "InvariantConsistent ((getM state) @ [(literal, decision)])"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)"
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"
  "¬ literal el (getQ state)"
shows
  "let state' = (assertLiteral literal decision state) in
      InvariantQCharacterization (getConflictFlag state') (getQ state') (getF state') (getM state')"
proof-
  let ?state' = "assertLiteral literal decision state"
  have "InvariantQCharacterization (getConflictFlag ?state') (removeAll literal (getQ ?state')) (getF ?state') (getM ?state')"
    using assms
    using InvariantQCharacterizationAfterAssertLiteral
    by (simp add: Let_def)
  moreover
  have "¬ literal el (getQ ?state')"
    using assms
    using assertedLiteralIsNotUnit[of "state" "literal" "decision"]
    by (simp add: Let_def)
  hence "removeAll literal (getQ ?state') = getQ ?state'"
    using removeAll_id[of "literal" "getQ ?state'"]
    by simp
  ultimately
  show ?thesis
    by (simp add: Let_def)
qed

lemma InvariantUniqQAfterAssertLiteral:
assumes
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantUniqQ (getQ state)"
shows
  "let state' = assertLiteral literal decision state in
      InvariantUniqQ (getQ state')"
using assms
using InvariantUniqQAfterNotifyWatchesLoop[of "stategetM := getM state @ [(literal, decision)]"
"getWatchList (stategetM := getM state @ [(literal, decision)]) (opposite literal)"
"opposite literal" "[]"]
unfolding assertLiteral_def
unfolding notifyWatches_def
unfolding InvariantWatchListsContainOnlyClausesFromF_def  
by (auto simp add: Let_def)

lemma InvariantsNoDecisionsWhenConflictNorUnitAfterAssertLiteral:
assumes
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)"
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"
  "InvariantNoDecisionsWhenConflict (getF state) (getM state) (currentLevel (getM state))"
  "InvariantNoDecisionsWhenUnit (getF state) (getM state) (currentLevel (getM state))"
  "decision  ¬ (getConflictFlag state)  (getQ state) = []"
shows
  "let state' = assertLiteral literal decision state in
       InvariantNoDecisionsWhenConflict (getF state') (getM state') (currentLevel (getM state'))  
       InvariantNoDecisionsWhenUnit (getF state') (getM state') (currentLevel (getM state'))"
proof-
  {
    let ?state' = "assertLiteral literal decision state"
    fix level
    assume "level < currentLevel (getM ?state')"
    have "¬ formulaFalse (getF ?state') (elements (prefixToLevel level (getM ?state')))  
          ¬ (clause literal. clause el (getF ?state') 
                isUnitClause clause literal (elements (prefixToLevel level (getM ?state'))))" 
    proof (cases "level < currentLevel (getM state)")
      case True
      hence "prefixToLevel level (getM ?state') = prefixToLevel level (getM state)"
        using assms
        using assertLiteralEffect[of "state" "literal" "decision"]
        by (auto simp add: prefixToLevelAppend)
      moreover
      have "¬ formulaFalse (getF state) (elements (prefixToLevel level (getM state)))"
        using ‹InvariantNoDecisionsWhenConflict (getF state) (getM state) (currentLevel (getM state))
        using level < currentLevel (getM state)
        unfolding InvariantNoDecisionsWhenConflict_def
        by simp
      moreover
      have "¬ (clause literal. clause el (getF state)  
                isUnitClause clause literal (elements (prefixToLevel level (getM state))))"
        using ‹InvariantNoDecisionsWhenUnit (getF state) (getM state) (currentLevel (getM state))
        using level < currentLevel (getM state)
        unfolding InvariantNoDecisionsWhenUnit_def
        by simp
      ultimately
      show ?thesis
        using assms
        using assertLiteralEffect[of "state" "literal" "decision"]
        by auto
    next
      case False
      thus ?thesis
      proof (cases "decision")
        case False
        hence "currentLevel (getM ?state') = currentLevel (getM state)"
          using assms
          using assertLiteralEffect[of "state" "literal" "decision"]
          unfolding currentLevel_def
          by (auto simp add: markedElementsAppend)
        thus ?thesis 
          using ¬ (level < currentLevel (getM state))
          using level < currentLevel (getM ?state')
          by simp
      next
        case True
        hence "currentLevel (getM ?state') = currentLevel (getM state) + 1"
          using assms
          using assertLiteralEffect[of "state" "literal" "decision"]
          unfolding currentLevel_def
          by (auto simp add: markedElementsAppend)
        hence "level = currentLevel (getM state)"
          using ¬ (level < currentLevel (getM state))
          using level < currentLevel (getM ?state')
          by simp
        hence "prefixToLevel level (getM ?state') = (getM state)"
          using decision
          using assms
          using assertLiteralEffect[of "state" "literal" "decision"]
          using prefixToLevelAppend[of "currentLevel (getM state)" "getM state" "[(literal, True)]"]
          by auto
        thus ?thesis
          using decision
          using decision  ¬ (getConflictFlag state)  (getQ state) = []
          using ‹InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)       
          using ‹InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)
          unfolding InvariantConflictFlagCharacterization_def
          unfolding InvariantQCharacterization_def
          using assms
          using assertLiteralEffect[of "state" "literal" "decision"]
          by simp
      qed
    qed
  } thus ?thesis
    unfolding InvariantNoDecisionsWhenConflict_def
    unfolding InvariantNoDecisionsWhenUnit_def
    by auto
qed



lemma InvariantVarsQAfterAssertLiteral:
assumes
  "InvariantConsistent ((getM state) @ [(literal, decision)])"
  "InvariantUniq ((getM state) @ [(literal, decision)])"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)"
  "InvariantWatchListsUniq (getWatchList state)"
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"  
  "InvariantVarsQ (getQ state) F0 Vbl"
  "InvariantVarsF (getF state) F0 Vbl"
shows  
  "let state' = assertLiteral literal decision state in
     InvariantVarsQ (getQ state') F0 Vbl"
proof-
  let ?Q' = "{ul. uc. uc el (getF state) 
                  (opposite literal) el uc  isUnitClause uc ul (elements (getM state) @ [literal])}"
  let ?state' = "assertLiteral literal decision state"
  have "vars ?Q'  vars (getF state)"
  proof
    fix vbl::Variable
    assume "vbl  vars ?Q'"
    then obtain ul::Literal
      where "ul  ?Q'" "var ul = vbl"
      by auto
    then obtain uc::Clause
      where "uc el (getF state)"  "isUnitClause uc ul (elements (getM state) @ [literal])"
      by auto
    hence "vars uc  vars (getF state)" "var ul  vars uc"
      using formulaContainsItsClausesVariables[of "uc" "getF state"]
      using clauseContainsItsLiteralsVariable[of "ul" "uc"]
      unfolding isUnitClause_def
      by auto
    thus "vbl  vars (getF state)"
      using ‹var ul = vbl
      by auto
  qed
  thus ?thesis
    using assms
    using assertLiteralQEffect[of "state" "literal" "decision"]
    using varsClauseVarsSet[of "getQ ?state'"]
    using varsClauseVarsSet[of "getQ state"]
    unfolding InvariantVarsQ_def
    unfolding InvariantVarsF_def
    by (auto simp add: Let_def)
qed

end

Theory UnitPropagate

theory UnitPropagate
imports AssertLiteral
begin
(*********************************************************************************)
(*    A P P L Y    U N I T    P R O P A G A T E                                  *)
(*********************************************************************************)

lemma applyUnitPropagateEffect:
assumes
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"

  "¬ (getConflictFlag state)"
  "getQ state  []"
shows
  "let uLiteral = hd (getQ state) in
   let state' = applyUnitPropagate state in
       uClause. formulaEntailsClause (getF state) uClause  
                 isUnitClause uClause uLiteral (elements (getM state))  
                 (getM state') = (getM state) @ [(uLiteral, False)]"
proof-
  let ?uLiteral = "hd (getQ state)"
  obtain uClause
    where "uClause el (getF state)" "isUnitClause uClause ?uLiteral (elements (getM state))"
    using assms
    unfolding InvariantQCharacterization_def
    by force
  thus ?thesis
    using assms
    using assertLiteralEffect[of "state" "?uLiteral" "False"]
    unfolding applyUnitPropagate_def
    using formulaEntailsItsClauses[of "uClause" "getF state"]
    by (auto simp add: Let_def )
qed

lemma InvariantConsistentAfterApplyUnitPropagate:
assumes
  "InvariantConsistent (getM state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"
  "getQ state  []"
  "¬ (getConflictFlag state)"
shows
  "let state' = applyUnitPropagate state in
     InvariantConsistent (getM state')
  "
proof-
  let ?uLiteral = "hd (getQ state)"
  let ?state' = "applyUnitPropagate state"
  obtain uClause 
    where "isUnitClause uClause ?uLiteral (elements (getM state))" and
    "(getM ?state') = (getM state) @ [(?uLiteral, False)]"
    using assms
    using applyUnitPropagateEffect[of "state"]
    by (auto simp add: Let_def)
  thus ?thesis
    using assms
    using InvariantConsistentAfterUnitPropagate[of "getM state" "uClause" "?uLiteral" "getM ?state'"]
    by (auto simp add: Let_def)
qed

lemma InvariantUniqAfterApplyUnitPropagate:
assumes
  "InvariantUniq (getM state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"
  "getQ state  []"
  "¬ (getConflictFlag state)"
shows
  "let state' = applyUnitPropagate state in
     InvariantUniq (getM state')
  "
proof-
  let ?uLiteral = "hd (getQ state)"
  let ?state' = "applyUnitPropagate state"
  obtain uClause 
    where "isUnitClause uClause ?uLiteral (elements (getM state))" and
    "(getM ?state') = (getM state) @ [(?uLiteral, False)]"
    using assms
    using applyUnitPropagateEffect[of "state"]
    by (auto simp add: Let_def)
  thus ?thesis
    using assms
    using InvariantUniqAfterUnitPropagate[of "getM state" "uClause" "?uLiteral" "getM ?state'"]
    by (auto simp add: Let_def)
qed

lemma InvariantWatchCharacterizationAfterApplyUnitPropagate:
assumes
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"
  "(getQ state)  []"
  "¬ (getConflictFlag state)"
shows
  "let state' = applyUnitPropagate state in
        InvariantWatchCharacterization (getF state') (getWatch1 state') (getWatch2 state') (getM state')"
proof-
  let ?uLiteral = "hd (getQ state)"
  let ?state' = "assertLiteral ?uLiteral False state"
  let ?state'' = "applyUnitPropagate state"
  have "InvariantConsistent (getM ?state')"
    using assms
    using InvariantConsistentAfterApplyUnitPropagate[of "state"]
    unfolding applyUnitPropagate_def
    by (auto simp add: Let_def)
  moreover
  have "InvariantUniq (getM ?state')"
    using assms
    using InvariantUniqAfterApplyUnitPropagate[of "state"]
    unfolding applyUnitPropagate_def
    by (auto simp add: Let_def)
  ultimately
  show ?thesis
    using assms
    using InvariantWatchCharacterizationAfterAssertLiteral[of "state" "?uLiteral" "False"]
    using assertLiteralEffect
    unfolding applyUnitPropagate_def
    by (simp add: Let_def)
qed

lemma InvariantConflictFlagCharacterizationAfterApplyUnitPropagate:
assumes
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)"
  "¬ getConflictFlag state"
  "getQ state  []"
shows
  "let state' = (applyUnitPropagate state) in
      InvariantConflictFlagCharacterization (getConflictFlag state') (getF state') (getM state')"
proof-
  let ?uLiteral = "hd (getQ state)"
  let ?state' = "assertLiteral ?uLiteral False state"
  let ?state'' = "applyUnitPropagate state"
  have "InvariantConsistent (getM ?state')"
    using assms
    using InvariantConsistentAfterApplyUnitPropagate[of "state"]
    unfolding applyUnitPropagate_def
    by (auto simp add: Let_def)
  moreover
  have "InvariantUniq (getM ?state')"
    using assms
    using InvariantUniqAfterApplyUnitPropagate[of "state"]
    unfolding applyUnitPropagate_def
    by (auto simp add: Let_def)
  ultimately
  show ?thesis
    using assms
    using InvariantConflictFlagCharacterizationAfterAssertLiteral[of "state" "?uLiteral" "False"]
    using assertLiteralEffect
    unfolding applyUnitPropagate_def
    by (simp add: Let_def)
qed


lemma InvariantConflictClauseCharacterizationAfterApplyUnitPropagate:
assumes
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)"
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchListsUniq (getWatchList state)"
  "¬ getConflictFlag state"
shows
   "let state' = applyUnitPropagate state in
    InvariantConflictClauseCharacterization (getConflictFlag state') (getConflictClause state') (getF state') (getM state')"
using assms
using InvariantConflictClauseCharacterizationAfterAssertLiteral[of "state" "hd (getQ state)" "False"]
unfolding applyUnitPropagate_def
unfolding InvariantWatchesEl_def
unfolding InvariantWatchListsContainOnlyClausesFromF_def
unfolding InvariantWatchListsCharacterization_def
unfolding InvariantWatchListsUniq_def
unfolding InvariantConflictClauseCharacterization_def
by (simp add: Let_def)
  
lemma InvariantQCharacterizationAfterApplyUnitPropagate:
assumes
  "InvariantConsistent (getM state)"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)"
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"
  "InvariantUniqQ (getQ state)"
  "(getQ state)  []"
  "¬ (getConflictFlag state)"
shows
  "let state'' = applyUnitPropagate state in
     InvariantQCharacterization (getConflictFlag state'') (getQ state'') (getF state'') (getM state'')"
proof-
  let ?uLiteral = "hd (getQ state)"
  let ?state' = "assertLiteral ?uLiteral False state"
  let ?state'' = "applyUnitPropagate state"
  have "InvariantConsistent (getM ?state')"
    using assms
    using InvariantConsistentAfterApplyUnitPropagate[of "state"]
    unfolding applyUnitPropagate_def
    by (auto simp add: Let_def)
  hence "InvariantQCharacterization (getConflictFlag ?state') (removeAll ?uLiteral (getQ ?state')) (getF ?state') (getM ?state')"
    using assms
    using InvariantQCharacterizationAfterAssertLiteral[of "state" "?uLiteral" "False"]
    using assertLiteralEffect[of "state" "?uLiteral" "False"]
    by (simp add: Let_def)
  moreover
  have "InvariantUniqQ (getQ ?state')"
    using assms
    using InvariantUniqQAfterAssertLiteral[of "state" "?uLiteral" "False"]
    by (simp add: Let_def)

  have "?uLiteral = (hd (getQ ?state'))"
  proof-
    obtain s 
      where "(getQ state) @ s = getQ ?state'"
      using assms
      using assertLiteralEffect[of "state" "?uLiteral" "False"]
      unfolding isPrefix_def
      by auto
    hence "getQ ?state' = (getQ state) @ s"
      by (rule sym)
    thus ?thesis
      using ‹getQ state  []
      using hd_append[of "getQ state" "s"]
      by auto
  qed
    
  hence "set (getQ ?state'') = set (removeAll ?uLiteral (getQ ?state'))"
    using assms
    using ‹InvariantUniqQ (getQ ?state')
    unfolding InvariantUniqQ_def
    using uniqHeadTailSet[of "getQ ?state'"]
    unfolding applyUnitPropagate_def
    by (simp add: Let_def)
  ultimately
  show ?thesis
    unfolding InvariantQCharacterization_def
    unfolding applyUnitPropagate_def
    by (simp add: Let_def)
qed


lemma InvariantUniqQAfterApplyUnitPropagate:
assumes
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)"
  "InvariantUniqQ (getQ state)"
  "getQ state  []"
shows
  "let state'' = applyUnitPropagate state in
      InvariantUniqQ (getQ state'')"
proof-
  let ?uLiteral = "hd (getQ state)"
  let ?state' = "assertLiteral ?uLiteral False state"
  let ?state'' = "applyUnitPropagate state"
  have "InvariantUniqQ (getQ ?state')"
    using assms
    using InvariantUniqQAfterAssertLiteral[of "state" "?uLiteral" "False"]
    by (simp add: Let_def)
  moreover
  obtain s 
    where "getQ state @ s = getQ ?state'"
    using assms
    using assertLiteralEffect[of "state" "?uLiteral" "False"]
    unfolding isPrefix_def
    by auto
  hence "getQ ?state' = getQ state @ s"
    by (rule sym)
  with ‹getQ state  []
  have "getQ ?state'  []"
    by simp
  ultimately
  show ?thesis
    using ‹getQ state  []
    unfolding InvariantUniqQ_def
    unfolding applyUnitPropagate_def
    using hd_Cons_tl[of "getQ ?state'"]
    using uniqAppendIff[of "[hd (getQ ?state')]" "tl (getQ ?state')"]
    by (simp add: Let_def)
qed

lemma InvariantNoDecisionsWhenConflictNorUnitAfterUnitPropagate:
assumes 
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)"
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)"
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"
  "InvariantNoDecisionsWhenConflict (getF state) (getM state) (currentLevel (getM state))"
  "InvariantNoDecisionsWhenUnit (getF state) (getM state) (currentLevel (getM state))"
shows
  "let state' = applyUnitPropagate state in
     InvariantNoDecisionsWhenConflict (getF state') (getM state') (currentLevel (getM state'))  
     InvariantNoDecisionsWhenUnit (getF state') (getM state') (currentLevel (getM state'))"
using assms
unfolding applyUnitPropagate_def
using InvariantsNoDecisionsWhenConflictNorUnitAfterAssertLiteral[of "state" "False" "hd (getQ state)"]
unfolding InvariantNoDecisionsWhenConflict_def
by (simp add: Let_def)


lemma InvariantGetReasonIsReasonAfterApplyUnitPropagate:
assumes
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)" and
  "InvariantUniqQ (getQ state)" and
  "InvariantGetReasonIsReason (getReason state) (getF state) (getM state) (set (getQ state))" and
  "getQ state  []" and
  "¬ getConflictFlag state" 
shows
  "let state' = applyUnitPropagate state in 
     InvariantGetReasonIsReason (getReason state') (getF state') (getM state') (set (getQ state'))"
proof-
  let ?state0 = "state  getM := getM state @ [(hd (getQ state), False)]"
  let ?state' = "assertLiteral (hd (getQ state)) False state"
  let ?state'' = "applyUnitPropagate state"

  have "InvariantGetReasonIsReason (getReason ?state0) (getF ?state0) (getM ?state0) (set (removeAll (hd (getQ ?state0)) (getQ ?state0)))"
  proof-

    {
      fix l::Literal
      assume *: "l el (elements (getM ?state0))  ¬ l el (decisions (getM ?state0))  elementLevel l (getM ?state0) > 0"
      hence " reason. getReason ?state0 l = Some reason  0  reason  reason < length (getF ?state0)  
               isReason (nth (getF ?state0) reason) l (elements (getM ?state0))"
      proof (cases "l el (elements (getM state))")
        case True
        from * 
        have "¬ l el (decisions (getM state))"
          by (auto simp add: markedElementsAppend)
        from *
        have "elementLevel l (getM state) > 0"
          using elementLevelAppend[of "l" "getM state" "[(hd (getQ state), False)]"]
          using l el (elements (getM state))
          by simp
        show ?thesis
          using ‹InvariantGetReasonIsReason (getReason state) (getF state) (getM state) (set (getQ state))
          using l el (elements (getM state))
          using ¬ l el (decisions (getM state))
          using ‹elementLevel l (getM state) > 0
          unfolding InvariantGetReasonIsReason_def
          by (auto simp add: isReasonAppend)
      next
        case False
        with * 
        have "l = hd (getQ state)"
          by simp

        have "currentLevel (getM ?state0) > 0"
          using *
          using elementLevelLeqCurrentLevel[of "l" "getM ?state0"]
          by auto
        hence "currentLevel (getM state) > 0"
          unfolding currentLevel_def
          by (simp add: markedElementsAppend)
        moreover
        have "hd (getQ ?state0) el (getQ state)"
          using ‹getQ state  []
          by simp
        ultimately
        obtain reason
          where "getReason state (hd (getQ state)) = Some reason" "0  reason  reason < length (getF state)"
          "isUnitClause (nth (getF state) reason) (hd (getQ state)) (elements (getM state))  
           clauseFalse (nth (getF state) reason) (elements (getM state))" 
          using ‹InvariantGetReasonIsReason (getReason state) (getF state) (getM state) (set (getQ state))
          unfolding InvariantGetReasonIsReason_def
          by auto
        hence "isUnitClause (nth (getF state) reason) (hd (getQ state)) (elements (getM state))"
          using ¬ getConflictFlag state
          using ‹InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)
          unfolding InvariantConflictFlagCharacterization_def
          using nth_mem[of "reason" "getF state"]
          using formulaFalseIffContainsFalseClause[of "getF state" "elements (getM state)"]
          by simp
        thus ?thesis
          using ‹getReason state (hd (getQ state)) = Some reason 0  reason  reason < length (getF state)
          using isUnitClauseIsReason[of "nth (getF state) reason" "hd (getQ state)" "elements (getM state)" "[hd (getQ state)]"]
          using l = hd (getQ state)
          by simp
     qed
    }
    moreover
    {
      fix literal::Literal
      assume "currentLevel (getM ?state0) > 0"
      hence "currentLevel (getM state) > 0"
        unfolding currentLevel_def
        by (simp add: markedElementsAppend)

      assume"literal el removeAll (hd (getQ ?state0)) (getQ ?state0)"
      hence "literal  hd (getQ state)" "literal el getQ state"
        by auto
      
      then obtain reason
        where "getReason state literal = Some reason" "0  reason  reason < length (getF state)" and
        *: "isUnitClause (nth (getF state) reason) literal (elements (getM state))  
            clauseFalse (nth (getF state) reason) (elements (getM state))"
        using ‹currentLevel (getM state) > 0
        using ‹InvariantGetReasonIsReason (getReason state) (getF state) (getM state) (set (getQ state))
        unfolding InvariantGetReasonIsReason_def
        by auto
      hence " reason. getReason ?state0 literal = Some reason  0  reason  reason < length (getF ?state0)  
              (isUnitClause (nth (getF ?state0) reason) literal (elements (getM ?state0))  
               clauseFalse (nth (getF ?state0) reason) (elements (getM ?state0)))"
      proof (cases "isUnitClause (nth (getF state) reason) literal (elements (getM state))")
        case True
        show ?thesis
        proof (cases "opposite literal = hd (getQ state)")
          case True
          thus ?thesis
            using ‹isUnitClause (nth (getF state) reason) literal (elements (getM state))
            using ‹getReason state literal = Some reason
            using literal  hd (getQ state)
            using 0  reason  reason < length (getF state)
            unfolding isUnitClause_def
            by (auto simp add: clauseFalseIffAllLiteralsAreFalse)
        next
          case False
          thus ?thesis
            using ‹isUnitClause (nth (getF state) reason) literal (elements (getM state))
            using ‹getReason state literal = Some reason
            using literal  hd (getQ state)
            using 0  reason  reason < length (getF state)
            unfolding isUnitClause_def
            by auto
        qed
      next
        case False
        with * 
        have "clauseFalse (nth (getF state) reason) (elements (getM state))"
          by simp
        thus ?thesis
          using ‹getReason state literal = Some reason
          using 0  reason  reason < length (getF state)
          using clauseFalseAppendValuation[of "nth (getF state) reason" "elements (getM state)" "[hd (getQ state)]"]
          by auto
      qed
    }
    ultimately
    show ?thesis
      unfolding InvariantGetReasonIsReason_def
      by auto
  qed

  hence "InvariantGetReasonIsReason (getReason ?state') (getF ?state') (getM ?state') (set (removeAll (hd (getQ state)) (getQ state))  (set (getQ ?state') - set (getQ state)))"
    using assms
    unfolding assertLiteral_def
    unfolding notifyWatches_def
    using InvariantGetReasonIsReasonAfterNotifyWatches[of  
      "?state0" "getWatchList ?state0 (opposite (hd (getQ state)))"  "opposite (hd (getQ state))" "getM state" "False"
      "set (removeAll (hd (getQ ?state0)) (getQ ?state0))" "[]"]
    unfolding InvariantWatchListsContainOnlyClausesFromF_def
    unfolding InvariantWatchListsCharacterization_def
    unfolding InvariantWatchListsUniq_def
    by (auto simp add: Let_def)

  obtain s 
    where "getQ state @ s = getQ ?state'"
    using assms
    using assertLiteralEffect[of "state" "hd (getQ state)" "False"]
    unfolding isPrefix_def
    by auto
  hence "getQ ?state' = getQ state @ s"
    by simp
  hence "hd (getQ ?state') = hd (getQ state)"
    using hd_append2[of "getQ state" "s"]
    using ‹getQ state  []
    by simp

  have " set (removeAll (hd (getQ state)) (getQ state))  (set (getQ ?state') - set (getQ state)) = 
         set (removeAll (hd (getQ state)) (getQ ?state'))"
    using ‹getQ ?state' = getQ state @ s
    using ‹getQ state  []
    by auto

  have "uniq (getQ ?state')"
    using assms
    using InvariantUniqQAfterAssertLiteral[of "state" "hd (getQ state)" "False"]
    unfolding InvariantUniqQ_def
    by (simp add: Let_def)
  
  have "set (getQ ?state'') = set (removeAll (hd (getQ state)) (getQ ?state'))"
    using ‹uniq (getQ ?state')
    using ‹hd (getQ ?state') = hd (getQ state)
    using uniqHeadTailSet[of "getQ ?state'"]
    unfolding applyUnitPropagate_def
    by (simp add: Let_def)

  thus ?thesis
    using ‹InvariantGetReasonIsReason (getReason ?state') (getF ?state') (getM ?state') (set (removeAll (hd (getQ state)) (getQ state))  (set (getQ ?state') - set (getQ state)))
    using ‹set (getQ ?state'') = set (removeAll (hd (getQ state)) (getQ ?state'))
    using ‹set (removeAll (hd (getQ state)) (getQ state))  (set (getQ ?state') - set (getQ state)) = 
         set (removeAll (hd (getQ state)) (getQ ?state'))
    unfolding applyUnitPropagate_def
    by (simp add: Let_def)
qed

lemma InvariantEquivalentZLAfterApplyUnitPropagate:
assumes 
  "InvariantEquivalentZL (getF state) (getM state) Phi"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"

  "¬ (getConflictFlag state)"
  "getQ state  []"
shows
  "let state' = applyUnitPropagate state in
      InvariantEquivalentZL (getF state') (getM state') Phi
  "
proof-
  let ?uLiteral = "hd (getQ state)"
  let ?state' = "applyUnitPropagate state"
  let ?FM = "getF state @ val2form (elements (prefixToLevel 0 (getM state)))"
  let ?FM' = "getF ?state' @ val2form (elements (prefixToLevel 0 (getM ?state')))"


  obtain uClause 
    where "formulaEntailsClause (getF state) uClause" and 
    "isUnitClause uClause ?uLiteral (elements (getM state))" and
    "(getM ?state') = (getM state) @ [(?uLiteral, False)]"
    "(getF ?state') = (getF state)"
    using assms
    using applyUnitPropagateEffect[of "state"]
    unfolding applyUnitPropagate_def
    using assertLiteralEffect
    by (auto simp add: Let_def)
  note * = this

  show ?thesis
  proof (cases "currentLevel (getM state) = 0")
    case True
    hence "getM state = prefixToLevel 0 (getM state)"
      by (rule currentLevelZeroTrailEqualsItsPrefixToLevelZero)

    
    have "?FM' = ?FM @ [[?uLiteral]]"
      using *
      using (getM ?state') = (getM state) @ [(?uLiteral, False)]
      using prefixToLevelAppend[of "0" "getM state" "[(?uLiteral, False)]"]
      using ‹currentLevel (getM state) = 0
      using ‹getM state = prefixToLevel 0 (getM state)
      by (auto simp add: val2formAppend)

    have "formulaEntailsLiteral ?FM ?uLiteral"
      using *
      using unitLiteralIsEntailed [of "uClause" "?uLiteral" "elements (getM state)" "(getF state)"]
      using ‹InvariantEquivalentZL (getF state) (getM state) Phi
      using ‹getM state = prefixToLevel 0 (getM state)
      unfolding InvariantEquivalentZL_def
      by simp
    hence "formulaEntailsClause ?FM [?uLiteral]"
      unfolding formulaEntailsLiteral_def
      unfolding formulaEntailsClause_def
      by (auto simp add: clauseTrueIffContainsTrueLiteral)

    show ?thesis
      using ‹InvariantEquivalentZL (getF state) (getM state) Phi
      using ?FM' = ?FM @ [[?uLiteral]]
      using ‹formulaEntailsClause ?FM [?uLiteral]
      unfolding InvariantEquivalentZL_def
      using extendEquivalentFormulaWithEntailedClause[of "Phi" "?FM" "[?uLiteral]"]
      by (simp add: equivalentFormulaeSymmetry)
  next
    case False
    hence "?FM = ?FM'"
      using *
      using prefixToLevelAppend[of "0" "getM state" "[(?uLiteral, False)]"]
      by (simp add: Let_def)
    thus ?thesis
      using ‹InvariantEquivalentZL (getF state) (getM state) Phi
      unfolding InvariantEquivalentZL_def
      by (simp add: Let_def)
  qed
qed


lemma InvariantVarsQTl:
assumes
  "InvariantVarsQ Q F0 Vbl"
  "Q  []"
shows
  "InvariantVarsQ (tl Q) F0 Vbl"
proof-
  have "InvariantVarsQ ((hd Q) # (tl Q)) F0 Vbl"
    using assms
    by simp
  hence "{var (hd Q)}  vars (tl Q)  vars F0  Vbl"
    unfolding InvariantVarsQ_def
    by simp
  thus ?thesis
    unfolding InvariantVarsQ_def
    by simp
qed

lemma InvariantsVarsAfterApplyUnitPropagate:
assumes
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)" and
  "InvariantQCharacterization False (getQ state) (getF state) (getM state)" and
  "getQ state  []"
  "¬ getConflictFlag state"
  "InvariantVarsM (getM state) F0 Vbl" and
  "InvariantVarsQ (getQ state) F0 Vbl" and
  "InvariantVarsF (getF state) F0 Vbl"
shows
  "let state' = applyUnitPropagate state in
     InvariantVarsM (getM state') F0 Vbl  
     InvariantVarsQ (getQ state') F0 Vbl"
proof-
  let ?state' = "assertLiteral (hd (getQ state)) False state"
  let ?state'' = "applyUnitPropagate state"
  have "InvariantVarsQ (getQ ?state') F0 Vbl"
    using assms
    using InvariantConsistentAfterApplyUnitPropagate[of "state"]
    using InvariantUniqAfterApplyUnitPropagate[of "state"]
    using InvariantVarsQAfterAssertLiteral[of "state" "hd (getQ state)" "False" "F0" "Vbl"]
    using assertLiteralEffect[of "state" "hd (getQ state)" "False"]
    unfolding applyUnitPropagate_def
    by (simp add: Let_def)
  moreover
  have "(getQ ?state')  []"
    using assms
    using assertLiteralEffect[of "state" "hd (getQ state)" "False"]
    using ‹getQ state  []
    unfolding isPrefix_def
    by auto
  ultimately
  have "InvariantVarsQ (getQ ?state'') F0 Vbl"
    unfolding applyUnitPropagate_def
    using InvariantVarsQTl[of "getQ ?state'" F0 Vbl]
    by (simp add: Let_def)
  moreover
  have "var (hd (getQ state))  vars F0  Vbl"
    using ‹getQ state  []
    using ‹InvariantVarsQ (getQ state) F0 Vbl
    using hd_in_set[of "getQ state"]
    using clauseContainsItsLiteralsVariable[of "hd (getQ state)" "getQ state"]
    unfolding InvariantVarsQ_def
    by auto
  hence "InvariantVarsM (getM ?state'') F0 Vbl"
    using assms
    using assertLiteralEffect[of "state" "hd (getQ state)" "False"]
    using varsAppendValuation[of "elements (getM state)" "[hd (getQ state)]"]
    unfolding applyUnitPropagate_def
    unfolding InvariantVarsM_def
    by (simp add: Let_def)
  ultimately
  show ?thesis
    by (simp add: Let_def)
qed


(*********************************************************************************)
(*   E X H A U S T I V E   U N I T   P R O P A G A T E                           *)
(*********************************************************************************)

definition "lexLessState (Vbl::Variable set) == {(state1, state2). 
  (getM state1, getM state2)  lexLessRestricted Vbl}"

lemma exhaustiveUnitPropagateTermination:
fixes
  state::State and Vbl::"Variable set"
assumes 
  "InvariantUniq (getM state)"
  "InvariantConsistent (getM state)"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)"
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"
  "InvariantUniqQ (getQ state)"
  "InvariantVarsM (getM state) F0 Vbl"
  "InvariantVarsQ (getQ state) F0 Vbl"
  "InvariantVarsF (getF state) F0 Vbl"
  "finite Vbl"
shows
  "exhaustiveUnitPropagate_dom state"
using assms
proof (induct rule: wf_induct[of "lexLessState (vars F0  Vbl)"])
  case 1
  show ?case
    unfolding wf_eq_minimal
  proof-
    show "Q (state::State). state  Q  (stateMinQ. state'. (state', stateMin)  lexLessState (vars F0  Vbl)  state'  Q)"
    proof-
      {
        fix Q :: "State set" and state :: State
        assume "state  Q"
        let ?Q1 = "{M::LiteralTrail.  state. state  Q  (getM state) = M}"
        from state  Q
        have "getM state  ?Q1"
          by auto
        have "wf (lexLessRestricted (vars F0  Vbl))"
          using ‹finite Vbl
          using finiteVarsFormula[of "F0"]
          using  wfLexLessRestricted[of "vars F0  Vbl"]
          by simp
        with ‹getM state  ?Q1
        obtain Mmin where "Mmin  ?Q1" "M'. (M', Mmin)  lexLessRestricted (vars F0  Vbl)  M'  ?Q1"
          unfolding wf_eq_minimal
          apply (erule_tac x="?Q1" in allE)
          apply (erule_tac x="getM state" in allE)
          by auto 
        from Mmin  ?Q1 obtain stateMin
          where "stateMin  Q" "(getM stateMin) = Mmin"
          by auto
        have "state'. (state', stateMin)  lexLessState (vars F0  Vbl)  state'  Q"
        proof
          fix state'
          show "(state', stateMin)  lexLessState (vars F0  Vbl)  state'  Q"
          proof
            assume "(state', stateMin)  lexLessState (vars F0  Vbl)"
            hence "(getM state', getM stateMin)  lexLessRestricted (vars F0  Vbl)"
              unfolding lexLessState_def
              by auto
            from M'. (M', Mmin)  lexLessRestricted (vars F0  Vbl)  M'  ?Q1
              (getM state', getM stateMin)  lexLessRestricted (vars F0  Vbl) ‹getM stateMin = Mmin
            have "getM state'  ?Q1"
              by simp
            with ‹getM stateMin = Mmin
            show "state'  Q"
              by auto
          qed
        qed
        with stateMin  Q
        have " stateMin  Q. (state'. (state', stateMin)  lexLessState (vars F0  Vbl)  state'  Q)"
          by auto
      }
      thus ?thesis
        by auto
    qed
  qed
next
  case (2 state')
  note ih = this
  show ?case
  proof (cases "getQ state' = []  getConflictFlag state'")
    case False
    let ?state'' = "applyUnitPropagate state'"

    have "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state'') (getF ?state'')" and
      "InvariantWatchListsUniq (getWatchList ?state'')" and
      "InvariantWatchListsCharacterization (getWatchList ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
      "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')" and
      "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
      using ih
      using WatchInvariantsAfterAssertLiteral[of "state'" "hd (getQ state')" "False"]
      unfolding applyUnitPropagate_def
      by (auto simp add: Let_def)
    moreover
    have "InvariantWatchCharacterization (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') (getM ?state'')"
      using ih
      using InvariantWatchCharacterizationAfterApplyUnitPropagate[of "state'"]
      unfolding InvariantQCharacterization_def
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantQCharacterization (getConflictFlag ?state'') (getQ ?state'') (getF ?state'') (getM ?state'')"
      using ih
      using InvariantQCharacterizationAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantConflictFlagCharacterization (getConflictFlag ?state'') (getF ?state'') (getM ?state'')"
      using ih
      using InvariantConflictFlagCharacterizationAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantUniqQ (getQ ?state'')"
      using ih
      using InvariantUniqQAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantConsistent (getM ?state'')"
      using ih
      using InvariantConsistentAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantUniq (getM ?state'')"
      using ih
      using InvariantUniqAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantVarsM (getM ?state'') F0 Vbl" "InvariantVarsQ (getQ ?state'') F0 Vbl"
      using ih
      using ¬ (getQ state' = []  getConflictFlag state')
      using InvariantsVarsAfterApplyUnitPropagate[of "state'" "F0" "Vbl"]
      by (auto simp add: Let_def)
    moreover
    have "InvariantVarsF (getF ?state'') F0 Vbl"
      unfolding applyUnitPropagate_def
      using assertLiteralEffect[of "state'" "hd (getQ state')" "False"]
      using ih
      by (simp add: Let_def)
    moreover
    have "(?state'', state')  lexLessState (vars F0  Vbl)"
    proof-
      have "getM ?state'' = getM state' @ [(hd (getQ state'), False)]"
        unfolding applyUnitPropagate_def
        using ih
        using assertLiteralEffect[of "state'" "hd (getQ state')" "False"]
        by (simp add: Let_def)
      thus ?thesis
        unfolding lexLessState_def
        unfolding lexLessRestricted_def
        using lexLessAppend[of "[(hd (getQ state'), False)]" "getM state'"]
        using ‹InvariantConsistent (getM ?state'')
        unfolding InvariantConsistent_def
        using ‹InvariantConsistent (getM state')
        unfolding InvariantConsistent_def
        using ‹InvariantUniq (getM ?state'')
        unfolding InvariantUniq_def
        using ‹InvariantUniq (getM state')
        unfolding InvariantUniq_def
        using ‹InvariantVarsM (getM ?state'') F0 Vbl
        using ‹InvariantVarsM (getM state') F0 Vbl
        unfolding InvariantVarsM_def
        by simp
    qed
    ultimately
    have "exhaustiveUnitPropagate_dom ?state''"
      using ih
      by auto
    thus ?thesis
      using exhaustiveUnitPropagate_dom.intros[of "state'"]
      using False
      by simp
  next
    case True
    show ?thesis
      apply (rule exhaustiveUnitPropagate_dom.intros)
      using True
      by simp
  qed  
qed

lemma exhaustiveUnitPropagatePreservedVariables:
assumes
  "exhaustiveUnitPropagate_dom state"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)"
shows
  "let state' = exhaustiveUnitPropagate state in 
       (getSATFlag state') = (getSATFlag state)"
using assms
proof (induct state rule: exhaustiveUnitPropagate_dom.induct)
  case (step state')
  note ih = this
  show ?case
  proof (cases "(getConflictFlag state')  (getQ state') = []")
    case True
    with exhaustiveUnitPropagate.simps[of "state'"]
    have "exhaustiveUnitPropagate state' = state'"
      by simp
    thus ?thesis
      by (simp only: Let_def)
  next
    case False
    let ?state'' = "applyUnitPropagate state'"

    have "exhaustiveUnitPropagate state' = exhaustiveUnitPropagate ?state''"
      using exhaustiveUnitPropagate.simps[of "state'"]
      using False
      by simp
    moreover
    have "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state'') (getF ?state'')" and
      "InvariantWatchListsUniq (getWatchList ?state'')" and
      "InvariantWatchListsCharacterization (getWatchList ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
      "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')" and
      "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
      using ih
      using WatchInvariantsAfterAssertLiteral[of "state'" "hd (getQ state')" "False"]
      unfolding applyUnitPropagate_def
      by (auto simp add: Let_def)
    moreover
    have "getSATFlag ?state'' = getSATFlag state'"
      unfolding applyUnitPropagate_def
      using assertLiteralEffect[of "state'" "hd (getQ state')" "False"]
      using ih
      by (simp add: Let_def)
    ultimately
    show ?thesis
      using ih
      using False
      by (simp add: Let_def)
  qed
qed

lemma exhaustiveUnitPropagatePreservesCurrentLevel:
assumes
  "exhaustiveUnitPropagate_dom state"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)"
shows
  "let state' = exhaustiveUnitPropagate state in 
       currentLevel (getM state') = currentLevel (getM state)"
using assms
proof (induct state rule: exhaustiveUnitPropagate_dom.induct)
  case (step state')
  note ih = this
  show ?case
  proof (cases "(getConflictFlag state')  (getQ state') = []")
    case True
    with exhaustiveUnitPropagate.simps[of "state'"]
    have "exhaustiveUnitPropagate state' = state'"
      by simp
    thus ?thesis
      by (simp only: Let_def)
  next
    case False
    let ?state'' = "applyUnitPropagate state'"

    have "exhaustiveUnitPropagate state' = exhaustiveUnitPropagate ?state''"
      using exhaustiveUnitPropagate.simps[of "state'"]
      using False
      by simp
    moreover
    have "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state'') (getF ?state'')" and
      "InvariantWatchListsUniq (getWatchList ?state'')" and
      "InvariantWatchListsCharacterization (getWatchList ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
      "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')" and
      "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
      using ih
      using WatchInvariantsAfterAssertLiteral[of "state'" "hd (getQ state')" "False"]
      unfolding applyUnitPropagate_def
      by (auto simp add: Let_def)
    moreover
    have "currentLevel (getM state') = currentLevel (getM ?state'')"
      unfolding applyUnitPropagate_def
      using assertLiteralEffect[of "state'" "hd (getQ state')" "False"]
      using ih
      unfolding currentLevel_def
      by (simp add: Let_def markedElementsAppend)
    ultimately
    show ?thesis
      using ih
      using False
      by (simp add: Let_def)
  qed
qed


lemma InvariantsAfterExhaustiveUnitPropagate:
assumes
  "exhaustiveUnitPropagate_dom state"
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)"
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"
  "InvariantUniqQ (getQ state)"
  "InvariantVarsQ (getQ state) F0 Vbl"
  "InvariantVarsM (getM state) F0 Vbl"
  "InvariantVarsF (getF state) F0 Vbl"
shows
  "let state' = exhaustiveUnitPropagate state in 
       InvariantConsistent (getM state')  
       InvariantUniq (getM state')  
       InvariantWatchListsContainOnlyClausesFromF (getWatchList state') (getF state')  
       InvariantWatchListsUniq (getWatchList state')  
       InvariantWatchListsCharacterization (getWatchList state') (getWatch1 state') (getWatch2 state')  
       InvariantWatchesEl (getF state') (getWatch1 state') (getWatch2 state')  
       InvariantWatchesDiffer (getF state') (getWatch1 state') (getWatch2 state')  
       InvariantWatchCharacterization (getF state') (getWatch1 state') (getWatch2 state') (getM state')  
       InvariantConflictFlagCharacterization (getConflictFlag state') (getF state') (getM state')  
       InvariantQCharacterization (getConflictFlag state') (getQ state') (getF state') (getM state')  
       InvariantUniqQ (getQ state')  
       InvariantVarsQ (getQ state') F0 Vbl  
       InvariantVarsM (getM state') F0 Vbl  
       InvariantVarsF (getF state') F0 Vbl
"
using assms
proof (induct state rule: exhaustiveUnitPropagate_dom.induct)
  case (step state')
  note ih = this
  show ?case
  proof (cases "(getConflictFlag state')  (getQ state') = []")
    case True
    with exhaustiveUnitPropagate.simps[of "state'"]
    have "exhaustiveUnitPropagate state' = state'"
      by simp
    thus ?thesis
      using ih
      by (auto simp only: Let_def)
  next
    case False
    let ?state'' = "applyUnitPropagate state'"

    have "exhaustiveUnitPropagate state' = exhaustiveUnitPropagate ?state''"
      using exhaustiveUnitPropagate.simps[of "state'"]
      using False
      by simp
    moreover
    have "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state'') (getF ?state'')" and
      "InvariantWatchListsUniq (getWatchList ?state'')" and
      "InvariantWatchListsCharacterization (getWatchList ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
      "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')" and
      "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
      using ih
      using WatchInvariantsAfterAssertLiteral[of "state'" "hd (getQ state')" "False"]
      unfolding applyUnitPropagate_def
      by (auto simp add: Let_def)
    moreover
    have "InvariantWatchCharacterization (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') (getM ?state'')"
      using ih
      using InvariantWatchCharacterizationAfterApplyUnitPropagate[of "state'"]
      unfolding InvariantQCharacterization_def
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantQCharacterization (getConflictFlag ?state'') (getQ ?state'') (getF ?state'') (getM ?state'')"
      using ih
      using InvariantQCharacterizationAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantConflictFlagCharacterization (getConflictFlag ?state'') (getF ?state'') (getM ?state'')"
      using ih
      using InvariantConflictFlagCharacterizationAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantUniqQ (getQ ?state'')"
      using ih
      using InvariantUniqQAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantConsistent (getM ?state'')"
      using ih
      using InvariantConsistentAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantUniq (getM ?state'')"
      using ih
      using InvariantUniqAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantVarsM (getM ?state'') F0 Vbl" "InvariantVarsQ (getQ ?state'') F0 Vbl"
      using ih
      using ¬ (getConflictFlag state'  getQ state' = [])
      using InvariantsVarsAfterApplyUnitPropagate[of "state'" "F0" "Vbl"]
      by (auto simp add: Let_def)
    moreover
    have "InvariantVarsF (getF ?state'') F0 Vbl"
      unfolding applyUnitPropagate_def
      using assertLiteralEffect[of "state'" "hd (getQ state')" "False"]
      using ih
      by (simp add: Let_def)
    ultimately
    show ?thesis
      using ih
      using False
      by (simp add: Let_def)
  qed
qed

lemma InvariantConflictClauseCharacterizationAfterExhaustivePropagate:
assumes
  "exhaustiveUnitPropagate_dom state"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantConflictClauseCharacterization (getConflictFlag state) (getConflictClause state) (getF state) (getM state)"
shows
  "let state' = exhaustiveUnitPropagate state in
   InvariantConflictClauseCharacterization (getConflictFlag state') (getConflictClause state') (getF state') (getM state')"
using assms
proof (induct state rule: exhaustiveUnitPropagate_dom.induct)
  case (step state')
  note ih = this
  show ?case
  proof (cases "(getConflictFlag state')  (getQ state') = []")
    case True
    with exhaustiveUnitPropagate.simps[of "state'"]
    have "exhaustiveUnitPropagate state' = state'"
      by simp
    thus ?thesis
      using ih
      by (auto simp only: Let_def)
  next
    case False
    let ?state'' = "applyUnitPropagate state'"

    have "exhaustiveUnitPropagate state' = exhaustiveUnitPropagate ?state''"
      using exhaustiveUnitPropagate.simps[of "state'"]
      using False
      by simp
    moreover
    have "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state'') (getF ?state'')" and
      "InvariantWatchListsUniq (getWatchList ?state'')" and
      "InvariantWatchListsCharacterization (getWatchList ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
      "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')" and
      "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
      using ih(2) ih(3) ih(4) ih(5) ih(6) ih(7)
      using WatchInvariantsAfterAssertLiteral[of "state'" "hd (getQ state')" "False"]
      unfolding applyUnitPropagate_def
      by (auto simp add: Let_def)
    moreover
    have "InvariantConflictClauseCharacterization (getConflictFlag ?state'') (getConflictClause ?state'') (getF ?state'') (getM ?state'')"
      using ih(2) ih(3) ih(4) ih(5) ih(6)
      using ¬ (getConflictFlag state'  getQ state' = [])
      using InvariantConflictClauseCharacterizationAfterApplyUnitPropagate[of "state'"]
      by (auto simp add: Let_def)
    ultimately
    show ?thesis
      using ih(1) ih(2)
      using False
      by (simp only: Let_def) (blast)
  qed
qed

lemma InvariantsNoDecisionsWhenConflictNorUnitAfterExhaustivePropagate:
assumes
  "exhaustiveUnitPropagate_dom state"
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)"
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"
  "InvariantUniqQ (getQ state)"
  "InvariantNoDecisionsWhenConflict (getF state) (getM state) (currentLevel (getM state))"
  "InvariantNoDecisionsWhenUnit (getF state) (getM state) (currentLevel (getM state))"
shows
  "let state' = exhaustiveUnitPropagate state in
       InvariantNoDecisionsWhenConflict (getF state') (getM state') (currentLevel (getM state'))  
       InvariantNoDecisionsWhenUnit (getF state') (getM state') (currentLevel (getM state'))"
using assms
proof (induct state rule: exhaustiveUnitPropagate_dom.induct)
  case (step state')
  note ih = this
  show ?case
  proof (cases "(getConflictFlag state')  (getQ state') = []")
    case True
    with exhaustiveUnitPropagate.simps[of "state'"]
    have "exhaustiveUnitPropagate state' = state'"
      by simp
    thus ?thesis
      using ih
      by (auto simp only: Let_def)
  next
    case False
    let ?state'' = "applyUnitPropagate state'"

    have "exhaustiveUnitPropagate state' = exhaustiveUnitPropagate ?state''"
      using exhaustiveUnitPropagate.simps[of "state'"]
      using False
      by simp
    moreover
    have "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state'') (getF ?state'')" and
      "InvariantWatchListsUniq (getWatchList ?state'')" and
      "InvariantWatchListsCharacterization (getWatchList ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
      "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')" and
      "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
      using ih(5) ih(6) ih(7) ih(8) ih(9)
      using WatchInvariantsAfterAssertLiteral[of "state'" "hd (getQ state')" "False"]
      unfolding applyUnitPropagate_def
      by (auto simp add: Let_def)
    moreover
    have "InvariantWatchCharacterization (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') (getM ?state'')"
      using ih
      using InvariantWatchCharacterizationAfterApplyUnitPropagate[of "state'"]
      unfolding InvariantQCharacterization_def
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantQCharacterization (getConflictFlag ?state'') (getQ ?state'') (getF ?state'') (getM ?state'')"
      using ih
      using InvariantQCharacterizationAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantConflictFlagCharacterization (getConflictFlag ?state'') (getF ?state'') (getM ?state'')"
      using ih
      using InvariantConflictFlagCharacterizationAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantUniqQ (getQ ?state'')"
      using ih
      using InvariantUniqQAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantConsistent (getM ?state'')"
      using ih
      using InvariantConsistentAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantUniq (getM ?state'')"
      using ih
      using InvariantUniqAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantNoDecisionsWhenUnit (getF ?state'') (getM ?state'') (currentLevel (getM ?state''))"
         "InvariantNoDecisionsWhenConflict (getF ?state'') (getM ?state'') (currentLevel (getM ?state''))"
      using ih(5) ih(8) ih(11) ih(12) ih(14) ih(15)
      using InvariantNoDecisionsWhenConflictNorUnitAfterUnitPropagate[of "state'"]
      by (auto simp add: Let_def)
    ultimately
    show ?thesis
      using ih(1) ih(2)
      using False
      by (simp add: Let_def)
  qed
qed


lemma InvariantGetReasonIsReasonAfterExhaustiveUnitPropagate:
assumes
  "exhaustiveUnitPropagate_dom state"
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)"
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"
  "InvariantUniqQ (getQ state)" and
  "InvariantGetReasonIsReason (getReason state) (getF state) (getM state) (set (getQ state))"
shows
  "let state' = exhaustiveUnitPropagate state in 
       InvariantGetReasonIsReason (getReason state') (getF state') (getM state') (set (getQ state'))"
using assms
proof (induct state rule: exhaustiveUnitPropagate_dom.induct)
  case (step state')
  note ih = this
  show ?case
  proof (cases "(getConflictFlag state')  (getQ state') = []")
    case True
    with exhaustiveUnitPropagate.simps[of "state'"]
    have "exhaustiveUnitPropagate state' = state'"
      by simp
    thus ?thesis
      using ih
      by (auto simp only: Let_def)
  next
    case False
    let ?state'' = "applyUnitPropagate state'"

    have "exhaustiveUnitPropagate state' = exhaustiveUnitPropagate ?state''"
      using exhaustiveUnitPropagate.simps[of "state'"]
      using False
      by simp
    moreover
    have "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state'') (getF ?state'')" and
      "InvariantWatchListsUniq (getWatchList ?state'')" and
      "InvariantWatchListsCharacterization (getWatchList ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
      "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')" and
      "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
      using ih
      using WatchInvariantsAfterAssertLiteral[of "state'" "hd (getQ state')" "False"]
      unfolding applyUnitPropagate_def
      by (auto simp add: Let_def)
    moreover
    have "InvariantWatchCharacterization (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') (getM ?state'')"
      using ih
      using InvariantWatchCharacterizationAfterApplyUnitPropagate[of "state'"]
      unfolding InvariantQCharacterization_def
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantQCharacterization (getConflictFlag ?state'') (getQ ?state'') (getF ?state'') (getM ?state'')"
      using ih
      using InvariantQCharacterizationAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantConflictFlagCharacterization (getConflictFlag ?state'') (getF ?state'') (getM ?state'')"
      using ih
      using InvariantConflictFlagCharacterizationAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantUniqQ (getQ ?state'')"
      using ih
      using InvariantUniqQAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantConsistent (getM ?state'')"
      using ih
      using InvariantConsistentAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantUniq (getM ?state'')"
      using ih
      using InvariantUniqAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantGetReasonIsReason (getReason ?state'') (getF ?state'') (getM ?state'') (set (getQ ?state''))"
      using ih
      using InvariantGetReasonIsReasonAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    ultimately
    show ?thesis
      using ih
      using False
      by (simp add: Let_def)
  qed
qed


lemma InvariantEquivalentZLAfterExhaustiveUnitPropagate:
assumes
  "exhaustiveUnitPropagate_dom state"
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantEquivalentZL (getF state) (getM state) Phi"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)"
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"
  "InvariantUniqQ (getQ state)"
shows
  "let state' = exhaustiveUnitPropagate state in 
      InvariantEquivalentZL (getF state') (getM state') Phi
  "
using assms
proof (induct state rule: exhaustiveUnitPropagate_dom.induct)
  case (step state')
  note ih = this
  show ?case
  proof (cases "(getConflictFlag state')  (getQ state') = []")
    case True
    with exhaustiveUnitPropagate.simps[of "state'"]
    have "exhaustiveUnitPropagate state' = state'"
      by simp
    thus ?thesis
      using ih
      by (simp only: Let_def)
  next
    case False
    let ?state'' = "applyUnitPropagate state'"

    have "exhaustiveUnitPropagate state' = exhaustiveUnitPropagate ?state''"
      using exhaustiveUnitPropagate.simps[of "state'"]
      using False
      by simp
    moreover
    have "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state'') (getF ?state'')" and
      "InvariantWatchListsUniq (getWatchList ?state'')" and
      "InvariantWatchListsCharacterization (getWatchList ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
      "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')" and
      "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
      using ih
      using WatchInvariantsAfterAssertLiteral[of "state'" "hd (getQ state')" "False"]
      unfolding applyUnitPropagate_def
      by (auto simp add: Let_def)
    moreover
    have "InvariantWatchCharacterization (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') (getM ?state'')"
      using ih
      using InvariantWatchCharacterizationAfterApplyUnitPropagate[of "state'"]
      unfolding InvariantQCharacterization_def
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantQCharacterization (getConflictFlag ?state'') (getQ ?state'') (getF ?state'') (getM ?state'')"
      using ih
      using InvariantQCharacterizationAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantConflictFlagCharacterization (getConflictFlag ?state'') (getF ?state'') (getM ?state'')"
      using ih
      using InvariantConflictFlagCharacterizationAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantUniqQ (getQ ?state'')"
      using ih
      using InvariantUniqQAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantConsistent (getM ?state'')"
      using ih
      using InvariantConsistentAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantUniq (getM ?state'')"
      using ih
      using InvariantUniqAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantEquivalentZL (getF ?state'') (getM ?state'') Phi"
      using ih
      using InvariantEquivalentZLAfterApplyUnitPropagate[of "state'" "Phi"]
      using False
      by (simp add: Let_def)
    moreover
    have "currentLevel (getM state') = currentLevel (getM ?state'')"
      unfolding applyUnitPropagate_def
      using assertLiteralEffect[of "state'" "hd (getQ state')" "False"]
      using ih
      unfolding currentLevel_def
      by (simp add: Let_def markedElementsAppend)
    ultimately
    show ?thesis
      using ih
      using False
      by (auto simp only: Let_def)
  qed
qed

lemma conflictFlagOrQEmptyAfterExhaustiveUnitPropagate:
assumes
"exhaustiveUnitPropagate_dom state"
shows
"let state' = exhaustiveUnitPropagate state in
    (getConflictFlag state')  (getQ state' = [])"
using assms
proof (induct state rule: exhaustiveUnitPropagate_dom.induct)
  case (step state')
  note ih = this
  show ?case
  proof (cases "(getConflictFlag state')  (getQ state') = []")
    case True
    with exhaustiveUnitPropagate.simps[of "state'"]
    have "exhaustiveUnitPropagate state' = state'"
      by simp
    thus ?thesis
      using True
      by (simp only: Let_def)
  next
    case False
    let ?state'' = "applyUnitPropagate state'"

    have "exhaustiveUnitPropagate state' = exhaustiveUnitPropagate ?state''"
      using exhaustiveUnitPropagate.simps[of "state'"]
      using False
      by simp
    thus ?thesis
      using ih
      using False
      by (simp add: Let_def)
  qed
qed

end

Theory Initialization

theory Initialization
imports UnitPropagate
begin


(*********************************************************************************)
(*    A D D    C L A U S E                                                       *)
(*********************************************************************************)

lemma InvariantsAfterAddClause:
fixes state::State and clause :: Clause and Vbl :: "Variable set"
assumes
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)"
  "InvariantConflictClauseCharacterization (getConflictFlag state) (getConflictClause state) (getF state) (getM state)"
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"
  "InvariantUniqQ (getQ state)"
  "InvariantGetReasonIsReason (getReason state) (getF state) (getM state) (set (getQ state))"
  "currentLevel (getM state) = 0"
  "(getConflictFlag state)  (getQ state) = []"
  "InvariantVarsM (getM state) F0 Vbl"
  "InvariantVarsQ (getQ state) F0 Vbl"
  "InvariantVarsF (getF state) F0 Vbl"
  "finite Vbl"
  "vars clause  vars F0"
shows
  "let state' = (addClause clause state) in
      InvariantConsistent (getM state')  
      InvariantUniq (getM state')  
      InvariantWatchListsContainOnlyClausesFromF (getWatchList state') (getF state')  
      InvariantWatchListsUniq (getWatchList state')  
      InvariantWatchListsCharacterization (getWatchList state') (getWatch1 state') (getWatch2 state')  
      InvariantWatchesEl (getF state') (getWatch1 state') (getWatch2 state')  
      InvariantWatchesDiffer (getF state') (getWatch1 state') (getWatch2 state')  
      InvariantWatchCharacterization (getF state') (getWatch1 state') (getWatch2 state') (getM state')  
      InvariantConflictFlagCharacterization (getConflictFlag state') (getF state') (getM state')  
      InvariantConflictClauseCharacterization (getConflictFlag state') (getConflictClause state') (getF state') (getM state')  
      InvariantQCharacterization (getConflictFlag state') (getQ state') (getF state') (getM state')  
      InvariantGetReasonIsReason (getReason state') (getF state') (getM state') (set (getQ state'))  
      InvariantUniqQ (getQ state')  
      InvariantVarsQ (getQ state') F0 Vbl  
      InvariantVarsM (getM state') F0 Vbl  
      InvariantVarsF (getF state') F0 Vbl  
      currentLevel (getM state') = 0  
      ((getConflictFlag state')  (getQ state') = [])
"
proof-
  let ?clause' = "remdups (removeFalseLiterals clause (elements (getM state)))"

  have *: " l. l el ?clause'  ¬ literalFalse l (elements (getM state))"
    unfolding removeFalseLiterals_def
    by auto

  have "vars ?clause'  vars clause"
    using varsSubsetValuation[of "?clause'" "clause"]
    unfolding removeFalseLiterals_def
    by auto
  hence "vars ?clause'  vars F0"
    using ‹vars clause  vars F0
    by simp

  show ?thesis
  proof (cases "clauseTrue ?clause' (elements (getM state))")
    case True
    thus ?thesis
      using assms
      unfolding addClause_def
      by simp
  next
    case False
    show ?thesis
    proof (cases "?clause' = []")
      case True
      thus ?thesis
        using assms
        using ¬ clauseTrue ?clause' (elements (getM state))
        unfolding addClause_def
        by simp
    next
      case False
      thus ?thesis
      proof (cases "length ?clause' = 1")
        case True
        let ?state' = "assertLiteral (hd ?clause') False state"
        have "addClause clause state = exhaustiveUnitPropagate ?state'"
          using ¬ clauseTrue ?clause' (elements (getM state))
          using ¬ ?clause' = []
          using ‹length ?clause' = 1
          unfolding addClause_def
          by (simp add: Let_def)
        moreover
        from ?clause'  []
        have "hd ?clause'  set ?clause'"
          using hd_in_set[of "?clause'"]
          by simp
        with *
        have "¬ literalFalse (hd ?clause') (elements (getM state))"
          by simp
        hence "consistent (elements ((getM state) @ [(hd ?clause', False)]))"
          using assms
          unfolding InvariantConsistent_def
          using consistentAppendElement[of "elements (getM state)" "hd ?clause'"]
          by simp
        hence "consistent (elements (getM ?state'))"
          using assms
          using assertLiteralEffect[of "state" "hd ?clause'" "False"]
          by simp
        moreover
        from ¬ clauseTrue ?clause' (elements (getM state))
        have "uniq (elements (getM ?state'))"
          using assms
          using assertLiteralEffect[of "state" "hd ?clause'" "False"]
          using ‹hd ?clause'  set ?clause'
          unfolding InvariantUniq_def
          by (simp add: uniqAppendIff clauseTrueIffContainsTrueLiteral)
        moreover
        have "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state') (getF ?state')" and
          "InvariantWatchListsUniq (getWatchList ?state')" and
          "InvariantWatchListsCharacterization (getWatchList ?state') (getWatch1 ?state') (getWatch2 ?state')"
          "InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state')" and
          "InvariantWatchesDiffer (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
          using assms
          using WatchInvariantsAfterAssertLiteral[of "state" "hd ?clause'" "False"]
          by (auto simp add: Let_def)
        moreover
        have "InvariantWatchCharacterization (getF ?state') (getWatch1 ?state') (getWatch2 ?state') (getM ?state')"
          using assms
          using InvariantWatchCharacterizationAfterAssertLiteral[of "state" "hd ?clause'" "False"]
          using ‹uniq (elements (getM ?state'))
          using ‹consistent (elements (getM ?state'))
          unfolding InvariantConsistent_def
          unfolding InvariantUniq_def
          using assertLiteralEffect[of "state" "hd ?clause'" "False"]
          by (simp add: Let_def)
        moreover
        have "InvariantConflictFlagCharacterization (getConflictFlag ?state') (getF ?state') (getM ?state')"
          using assms
          using InvariantConflictFlagCharacterizationAfterAssertLiteral[of "state" "hd ?clause'" "False"]
          using ‹consistent (elements (getM ?state'))
          unfolding InvariantConsistent_def
          using assertLiteralEffect[of "state" "hd ?clause'" "False"]
          by (simp add: Let_def)
        moreover
        have "InvariantConflictClauseCharacterization (getConflictFlag ?state') (getConflictClause ?state') (getF ?state') (getM ?state')"
          using assms
          using InvariantConflictClauseCharacterizationAfterAssertLiteral[of "state" "hd ?clause'" "False"]
          by (simp add: Let_def)
        moreover
        let ?state'' = "?state' getM := (getM ?state') @ [(hd ?clause', False)] "
        have "InvariantQCharacterization (getConflictFlag ?state') (getQ ?state') (getF ?state') (getM ?state')"
        proof (cases "getConflictFlag state")
          case True
          hence "getConflictFlag ?state'"
            using assms
            using assertLiteralConflictFlagEffect[of "state" "hd ?clause'" "False"]
            using ‹uniq (elements (getM ?state'))
            using ‹consistent (elements (getM ?state'))
            unfolding InvariantConsistent_def
            unfolding InvariantUniq_def
            using assertLiteralEffect[of "state" "hd ?clause'" "False"]
            by (auto simp add: Let_def)
          thus ?thesis
            using assms
            unfolding InvariantQCharacterization_def
            by simp
        next
          case False
          with (getConflictFlag state)  (getQ state) = []
          have "getQ state = []"
            by simp
          thus ?thesis
            using InvariantQCharacterizationAfterAssertLiteralNotInQ[of "state" "hd ?clause'" "False"]
            using assms
            using ‹uniq (elements (getM ?state'))
            using ‹consistent (elements (getM ?state'))
            unfolding InvariantConsistent_def
            unfolding InvariantUniq_def
            using assertLiteralEffect[of "state" "hd ?clause'" "False"]
            by (auto simp add: Let_def)
        qed
        moreover
        have "InvariantUniqQ (getQ ?state')"
          using assms
          using InvariantUniqQAfterAssertLiteral[of "state" "hd ?clause'" "False"]
          by (simp add: Let_def)
        moreover
        have "currentLevel (getM ?state') = 0"
          using assms
          using ¬ clauseTrue ?clause' (elements (getM state))
          using ¬ ?clause' = []
          using assertLiteralEffect[of "state" "hd ?clause'" "False"]
          unfolding addClause_def
          unfolding currentLevel_def
          by (simp add:Let_def markedElementsAppend)
        moreover
        hence "InvariantGetReasonIsReason (getReason ?state') (getF ?state') (getM ?state') (set (getQ ?state'))"
          unfolding InvariantGetReasonIsReason_def
          using elementLevelLeqCurrentLevel[of _ "getM ?state'"]
          by auto
        moreover
        have "var (hd ?clause')  vars F0"
          using ?clause'  []
          using hd_in_set[of "?clause'"]
          using ‹vars ?clause'  vars F0
          using clauseContainsItsLiteralsVariable[of "hd ?clause'" "?clause'"]
          by auto
        hence "InvariantVarsQ (getQ ?state') F0 Vbl"
          "InvariantVarsM (getM ?state') F0 Vbl"
          "InvariantVarsF (getF ?state') F0 Vbl"
          using ‹InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)
          using ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)
          using ‹InvariantWatchListsUniq (getWatchList state)
          using ‹InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)
          using ‹InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)
          using ‹InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)
          using ‹InvariantVarsF (getF state) F0 Vbl
          using ‹InvariantVarsM (getM state) F0 Vbl
          using ‹InvariantVarsQ (getQ state) F0 Vbl
          using ‹consistent (elements (getM ?state'))
          using ‹uniq (elements (getM ?state'))
          using assertLiteralEffect[of "state" "hd ?clause'" "False"]
          using varsAppendValuation[of "elements (getM state)" "[hd ?clause']"]
          using InvariantVarsQAfterAssertLiteral[of "state" "hd ?clause'" "False" "F0" "Vbl"]
          unfolding InvariantVarsM_def
          unfolding InvariantConsistent_def
          unfolding InvariantUniq_def
          by (auto simp add: Let_def)
        moreover
        have "exhaustiveUnitPropagate_dom ?state'"
          using exhaustiveUnitPropagateTermination[of "?state'" "F0" "Vbl"]
          using ‹InvariantUniqQ (getQ ?state')
          using ‹InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state') (getF ?state')
          using ‹InvariantWatchListsUniq (getWatchList ?state')
          using ‹InvariantWatchListsCharacterization (getWatchList ?state') (getWatch1 ?state') (getWatch2 ?state')
          using ‹InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state')
          using ‹InvariantWatchesDiffer (getF ?state') (getWatch1 ?state') (getWatch2 ?state')
          using ‹InvariantQCharacterization (getConflictFlag ?state') (getQ ?state') (getF ?state') (getM ?state')
          using ‹InvariantWatchCharacterization (getF ?state') (getWatch1 ?state') (getWatch2 ?state') (getM ?state')
          using ‹InvariantConflictFlagCharacterization (getConflictFlag ?state') (getF ?state') (getM ?state')
          using ‹consistent (elements (getM ?state'))
          using ‹uniq (elements (getM ?state'))
          using ‹finite Vbl
          using ‹InvariantVarsQ (getQ ?state') F0 Vbl
          using ‹InvariantVarsM (getM ?state') F0 Vbl
          using ‹InvariantVarsF (getF ?state') F0 Vbl
          unfolding InvariantConsistent_def
          unfolding InvariantUniq_def
          by simp
        ultimately
        show ?thesis
          using ‹exhaustiveUnitPropagate_dom ?state'
          using InvariantsAfterExhaustiveUnitPropagate[of "?state'"]
          using InvariantConflictClauseCharacterizationAfterExhaustivePropagate[of "?state'"]
          using conflictFlagOrQEmptyAfterExhaustiveUnitPropagate[of "?state'"]
          using exhaustiveUnitPropagatePreservesCurrentLevel[of "?state'"]
          using InvariantGetReasonIsReasonAfterExhaustiveUnitPropagate[of "?state'"]
          using assms
          using assertLiteralEffect[of "state" "hd ?clause'" "False"]
          unfolding InvariantConsistent_def
          unfolding InvariantUniq_def
          by (auto simp only:Let_def)
      next
        case False
        thus ?thesis
        proof (cases "clauseTautology ?clause'")
          case True
          thus ?thesis
            using assms
            using ¬ ?clause' = []
            using ¬ clauseTrue ?clause' (elements (getM state))
            using ‹length ?clause'  1
            unfolding addClause_def
            by simp
        next
          case False
          from ¬ ?clause' = [] ‹length ?clause'  1
          have "length ?clause' > 1"
            by (induct (?clause')) auto

          hence "nth ?clause' 0  nth ?clause' 1"
            using distinct_remdups[of "?clause'"]
            using nth_eq_iff_index_eq[of "?clause'" "0" "1"]
            using ¬ ?clause' = []
            by auto

          let ?state' = "let clauseIndex = length (getF state) in
                         let state'   = state getF := (getF state) @ [?clause'] in
                         let state''  = setWatch1 clauseIndex (nth ?clause' 0) state' in
                         let state''' = setWatch2 clauseIndex (nth ?clause' 1) state'' in
                         state'''"

          have "InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
            using ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)
            using ‹length ?clause' > 1
            using ?clause'  []
            using nth_mem[of "0" "?clause'"]
            using nth_mem[of "1" "?clause'"]
            unfolding InvariantWatchesEl_def
            unfolding setWatch1_def
            unfolding setWatch2_def
            by (auto simp add: Let_def nth_append)
          moreover
          have "InvariantWatchesDiffer (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
            using ‹InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)
            using ‹nth ?clause' 0  nth ?clause' 1
            unfolding InvariantWatchesDiffer_def
            unfolding setWatch1_def
            unfolding setWatch2_def
            by (auto simp add: Let_def)
          moreover
          have "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state') (getF ?state')"
            using ‹InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)
            unfolding InvariantWatchListsContainOnlyClausesFromF_def
            unfolding setWatch1_def
            unfolding setWatch2_def
            by (auto simp add:Let_def) (force)+
          moreover
          have "InvariantWatchListsCharacterization (getWatchList ?state') (getWatch1 ?state') (getWatch2 ?state')"
            using ‹InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)
            using ‹InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)
            using ‹nth ?clause' 0  nth ?clause' 1
            unfolding InvariantWatchListsCharacterization_def
            unfolding InvariantWatchListsContainOnlyClausesFromF_def
            unfolding setWatch1_def
            unfolding setWatch2_def
            by (auto simp add:Let_def)
          moreover
          have "InvariantWatchCharacterization (getF ?state') (getWatch1 ?state') (getWatch2 ?state') (getM ?state')"
          proof-
            {
              fix c
              assume "0  c  c < length (getF ?state')"
              fix www1 www2
              assume "Some www1 = (getWatch1 ?state' c)" "Some www2 = (getWatch2 ?state' c)"
              have "watchCharacterizationCondition www1 www2 (getM ?state') (nth (getF ?state') c)  
                    watchCharacterizationCondition www2 www1 (getM ?state') (nth (getF ?state') c)"
              proof (cases "c < length (getF state)")
                case True
                hence "(nth (getF ?state') c) = (nth (getF state) c)"
                  unfolding setWatch1_def
                  unfolding setWatch2_def
                  by (auto simp add: Let_def nth_append)
                have "Some www1 = (getWatch1 state c)" "Some www2 = (getWatch2 state c)"
                  using True
                  using ‹Some www1 = (getWatch1 ?state' c) ‹Some www2 = (getWatch2 ?state' c)
                  unfolding setWatch1_def
                  unfolding setWatch2_def
                  by (auto simp add: Let_def)
                thus ?thesis
                  using ‹InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)
                  unfolding InvariantWatchCharacterization_def
                  using (nth (getF ?state') c) = (nth (getF state) c)
                  using True
                  unfolding setWatch1_def
                  unfolding setWatch2_def
                  by (auto simp add: Let_def)
              next
                case False
                with 0  c  c < length (getF ?state')
                have "c = length (getF state)"
                  unfolding setWatch1_def
                  unfolding setWatch2_def
                  by (auto simp add: Let_def)
                from ‹InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state')
                obtain w1 w2 
                  where 
                  "w1 el ?clause'" "w2 el ?clause'"
                  "getWatch1 ?state' (length (getF state)) = Some w1"
                  "getWatch2 ?state' (length (getF state)) = Some w2"
                  unfolding InvariantWatchesEl_def
                  unfolding setWatch2_def
                  unfolding setWatch1_def
                  by (auto simp add: Let_def)
                hence "w1 = www1" and "w2 = www2"
                  using ‹Some www1 = (getWatch1 ?state' c) ‹Some www2 = (getWatch2 ?state' c)
                  using c = length (getF state)
                  by auto
                have "¬ literalFalse  w1 (elements (getM ?state'))" 
                  "¬ literalFalse w2 (elements (getM ?state'))"
                  using w1 el ?clause' w2 el ?clause'
                  using *
                  unfolding setWatch2_def
                  unfolding setWatch1_def
                  by (auto simp add: Let_def)
                thus ?thesis
                  using w1 = www1 w2 = www2
                  unfolding watchCharacterizationCondition_def
                  unfolding setWatch2_def
                  unfolding setWatch1_def
                  by (auto simp add: Let_def)
              qed
            } thus ?thesis
              unfolding InvariantWatchCharacterization_def
              by auto
          qed
          moreover 
          have " l. length (getF state)  set (getWatchList state l)"
            using ‹InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)            
            unfolding InvariantWatchListsContainOnlyClausesFromF_def
            by auto
          hence "InvariantWatchListsUniq (getWatchList ?state')"
            using ‹InvariantWatchListsUniq (getWatchList state)
            using ‹nth ?clause' 0  nth ?clause' 1
            unfolding InvariantWatchListsUniq_def
            unfolding setWatch1_def
            unfolding setWatch2_def
            by (auto simp add:Let_def uniqAppendIff)
          moreover
          from * 
          have "¬ clauseFalse ?clause' (elements (getM state))"
            using ?clause'  []
            by (auto simp add: clauseFalseIffAllLiteralsAreFalse)
          hence "InvariantConflictFlagCharacterization (getConflictFlag ?state') (getF ?state') (getM ?state')"
            using ‹InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)
            unfolding InvariantConflictFlagCharacterization_def
            unfolding setWatch1_def
            unfolding setWatch2_def
            by (auto simp add: Let_def formulaFalseIffContainsFalseClause)
          moreover
          have "¬ ( l. isUnitClause ?clause' l (elements (getM state)))"
          proof-
            {
              assume "¬ ?thesis"
              then obtain l
                where "isUnitClause ?clause' l (elements (getM state))"
                by auto
              hence "l el ?clause'"
                unfolding isUnitClause_def
                by simp
              have " l'. l' el ?clause'  l  l'"
              proof-
                from ‹length ?clause' > 1
                obtain a1::Literal and a2::Literal
                  where "a1 el ?clause'" "a2 el ?clause'" "a1  a2"
                  using lengthGtOneTwoDistinctElements[of "?clause'"]
                  by (auto simp add: uniqDistinct) (force)
                thus ?thesis
                proof (cases "a1 = l")
                  case True
                  thus ?thesis
                    using a1  a2 a2 el ?clause'
                    by auto
                next
                  case False
                  thus ?thesis
                    using a1 el ?clause'
                    by auto
                qed
              qed
              then obtain l'::Literal
                where "l  l'" "l' el ?clause'"
                by auto
              with * 
              have "¬ literalFalse l' (elements (getM state))"
                by simp
              hence "False"
                using ‹isUnitClause ?clause' l (elements (getM state))
                using l  l' l' el ?clause'
                unfolding isUnitClause_def
                by auto
            } thus ?thesis
              by auto
          qed
          hence "InvariantQCharacterization (getConflictFlag ?state') (getQ ?state') (getF ?state') (getM ?state')"
            using assms
            unfolding InvariantQCharacterization_def
            unfolding setWatch2_def
            unfolding setWatch1_def
            by (auto simp add: Let_def)
          moreover
          have "InvariantConflictClauseCharacterization (getConflictFlag state) (getConflictClause state) (getF state @ [?clause']) (getM state)"
          proof (cases "getConflictFlag state")
            case False
            thus ?thesis
              unfolding InvariantConflictClauseCharacterization_def
              by simp
          next
            case True
            hence "getConflictClause state < length (getF state)"
              using ‹InvariantConflictClauseCharacterization (getConflictFlag state) (getConflictClause state) (getF state) (getM state)
              unfolding InvariantConflictClauseCharacterization_def
              by (auto simp add: Let_def)
            hence "nth ((getF state) @ [?clause']) (getConflictClause state) = 
                   nth (getF state) (getConflictClause state)"
              by (simp add: nth_append)
            thus ?thesis
              using ‹InvariantConflictClauseCharacterization (getConflictFlag state) (getConflictClause state) (getF state) (getM state)
              unfolding InvariantConflictClauseCharacterization_def
              by (auto simp add: Let_def clauseFalseAppendValuation)
          qed
          moreover
          have "InvariantGetReasonIsReason (getReason ?state') (getF ?state') (getM ?state') (set (getQ ?state'))"
            using ‹currentLevel (getM state) = 0
            using elementLevelLeqCurrentLevel[of _ "getM state"]
            unfolding setWatch1_def
            unfolding setWatch2_def
            unfolding InvariantGetReasonIsReason_def
            by (simp add: Let_def)
          moreover
          have "InvariantVarsF (getF ?state') F0 Vbl"
            using ‹InvariantVarsF (getF state) F0 Vbl
            using ‹vars ?clause'  vars F0
            using varsAppendFormulae[of "getF state" "[?clause']"]
            unfolding setWatch2_def
            unfolding setWatch1_def
            unfolding InvariantVarsF_def
            by (auto simp add: Let_def)
          ultimately
          show ?thesis
            using assms
            using ‹length ?clause' > 1
            using ¬ ?clause' = []
            using ¬ clauseTrue ?clause' (elements (getM state))
            using ‹length ?clause'  1
            using ¬ clauseTautology ?clause'
            unfolding addClause_def
            unfolding setWatch1_def
            unfolding setWatch2_def
            by (auto simp add: Let_def)
        qed
      qed
    qed
  qed
qed


lemma InvariantEquivalentZLAfterAddClause:
fixes Phi :: Formula and clause :: Clause and state :: State and Vbl :: "Variable set"
assumes 
*:"(getSATFlag state = UNDEF  InvariantEquivalentZL (getF state) (getM state) Phi)  
   (getSATFlag state = FALSE  ¬ satisfiable Phi)"
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)"
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"
  "InvariantUniqQ (getQ state)"
  "(getConflictFlag state)  (getQ state) = []"
  "currentLevel (getM state) = 0"
  "InvariantVarsM (getM state) F0 Vbl"
  "InvariantVarsQ (getQ state) F0 Vbl"
  "InvariantVarsF (getF state) F0 Vbl"
  "finite Vbl"
  "vars clause  vars F0"
shows
"let state' = addClause clause state in
 let Phi' = Phi @ [clause] in
 let Phi'' = (if (clauseTautology clause) then Phi else Phi') in
 (getSATFlag state' = UNDEF  InvariantEquivalentZL (getF state') (getM state') Phi'')  
 (getSATFlag state' = FALSE  ¬satisfiable Phi'')"
proof-
  let ?clause' = "remdups (removeFalseLiterals clause (elements (getM state)))"

  from ‹currentLevel (getM state) = 0 
  have "getM state = prefixToLevel 0 (getM state)"
    by (rule currentLevelZeroTrailEqualsItsPrefixToLevelZero)

  have **: " l. l el ?clause'  ¬ literalFalse l (elements (getM state))"
    unfolding removeFalseLiterals_def
    by auto

  have "vars ?clause'  vars clause"
    using varsSubsetValuation[of "?clause'" "clause"]
    unfolding removeFalseLiterals_def
    by auto
  hence "vars ?clause'  vars F0"
    using ‹vars clause  vars F0
    by simp

  show ?thesis
  proof (cases "clauseTrue ?clause' (elements (getM state))")
    case True
    show ?thesis
    proof-
      from True 
      have "clauseTrue clause (elements (getM state))"
        using clauseTrueRemoveDuplicateLiterals
        [of "removeFalseLiterals clause (elements (getM state))" "elements (getM state)"]
        using clauseTrueRemoveFalseLiterals
        [of "elements (getM state)" "clause"]
        using ‹InvariantConsistent (getM state)
        unfolding InvariantConsistent_def
        by simp
      show ?thesis
      proof (cases "getSATFlag state = UNDEF")
        case True
        thus ?thesis
          using *
          using ‹clauseTrue clause (elements (getM state))
          using ‹getM state = prefixToLevel 0 (getM state)
          using satisfiedClauseCanBeRemoved
          [of "getF state" "(elements (prefixToLevel 0 (getM state)))" "Phi" "clause"]
          using ‹clauseTrue ?clause' (elements (getM state))
          unfolding addClause_def
          unfolding InvariantEquivalentZL_def
          by auto
      next
        case False
        thus ?thesis
          using *
          using ‹clauseTrue ?clause' (elements (getM state))
          using satisfiableAppend[of "Phi" "[clause]"]
          unfolding addClause_def
          by force
      qed
    qed
  next
    case False
    show ?thesis
    proof (cases "?clause' = []")
      case True
      show ?thesis
      proof (cases "getSATFlag state = UNDEF")
        case True
        thus ?thesis
          using *
          using falseAndDuplicateLiteralsCanBeRemoved
          [of "getF state" "(elements (prefixToLevel 0 (getM state)))" "[]" "Phi" "clause"]
          using ‹getM state = prefixToLevel 0 (getM state)
          using formulaWithEmptyClauseIsUnsatisfiable[of "(getF state @ val2form (elements (getM state)) @ [[]])"]
          using satisfiableEquivalent
          using ?clause' = []
          unfolding addClause_def
          unfolding InvariantEquivalentZL_def
          using satisfiableAppendTautology
          by auto
      next
        case False
        thus ?thesis
          using ?clause' = []
          using *
          using satisfiableAppend[of "Phi" "[clause]"]
          unfolding addClause_def
          by force
      qed
    next
      case False
      thus ?thesis
      proof (cases "length ?clause' = 1")
        case True
        from ‹length ?clause' = 1
        have "[hd ?clause'] = ?clause'"
          using lengthOneCharacterisation[of "?clause'"]
          by simp

        with ‹length ?clause' = 1
        have "val2form (elements (getM state)) @ [?clause'] = val2form ((elements (getM state)) @ ?clause')"
          using val2formAppend[of "elements (getM state)" "?clause'"]
          using val2formOfSingleLiteralValuation[of "?clause'"]
          by auto

        let ?state' = "assertLiteral (hd ?clause') False state"
        have "addClause clause state = exhaustiveUnitPropagate ?state'"
          using ¬ clauseTrue ?clause' (elements (getM state))
          using ¬ ?clause' = []
          using ‹length ?clause' = 1
          unfolding addClause_def
          by (simp add: Let_def)
        moreover
        from ?clause'  []
        have "hd ?clause'  set ?clause'"
          using hd_in_set[of "?clause'"]
          by simp
        with **
        have "¬ literalFalse (hd ?clause') (elements (getM state))"
          by simp
        hence "consistent (elements ((getM state) @ [(hd ?clause', False)]))"
          using assms
          unfolding InvariantConsistent_def
          using consistentAppendElement[of "elements (getM state)" "hd ?clause'"]
          by simp
        hence "consistent (elements (getM ?state'))"
          using assms
          using assertLiteralEffect[of "state" "hd ?clause'" "False"]
          by simp
        moreover
        from ¬ clauseTrue ?clause' (elements (getM state))
        have "uniq (elements (getM ?state'))"
          using assms
          using assertLiteralEffect[of "state" "hd ?clause'" "False"]
          using ‹hd ?clause'  set ?clause'
          unfolding InvariantUniq_def
          by (simp add: uniqAppendIff clauseTrueIffContainsTrueLiteral)
        moreover
        have "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state') (getF ?state')" and
          "InvariantWatchListsUniq (getWatchList ?state')" and
          "InvariantWatchListsCharacterization (getWatchList ?state') (getWatch1 ?state') (getWatch2 ?state')"
          "InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state')" and
          "InvariantWatchesDiffer (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
          using assms
          using WatchInvariantsAfterAssertLiteral[of "state" "hd ?clause'" "False"]
          by (auto simp add: Let_def)
        moreover
        have "InvariantWatchCharacterization (getF ?state') (getWatch1 ?state') (getWatch2 ?state') (getM ?state')"
          using assms
          using InvariantWatchCharacterizationAfterAssertLiteral[of "state" "hd ?clause'" "False"]
          using ‹uniq (elements (getM ?state'))
          using ‹consistent (elements (getM ?state'))
          unfolding InvariantConsistent_def
          unfolding InvariantUniq_def
          using assertLiteralEffect[of "state" "hd ?clause'" "False"]
          by (simp add: Let_def)
        moreover
        have "InvariantConflictFlagCharacterization (getConflictFlag ?state') (getF ?state') (getM ?state')"
          using assms
          using InvariantConflictFlagCharacterizationAfterAssertLiteral[of "state" "hd ?clause'" "False"]
          using ‹consistent (elements (getM ?state'))
          unfolding InvariantConsistent_def
          using assertLiteralEffect[of "state" "hd ?clause'" "False"]
          by (simp add: Let_def)
        moreover
        have "InvariantQCharacterization (getConflictFlag ?state') (getQ ?state') (getF ?state') (getM ?state')"
        proof (cases "getConflictFlag state")
          case True
          hence "getConflictFlag ?state'"
            using assms
            using assertLiteralConflictFlagEffect[of "state" "hd ?clause'" "False"]
            using ‹uniq (elements (getM ?state'))
            using ‹consistent (elements (getM ?state'))
            unfolding InvariantConsistent_def
            unfolding InvariantUniq_def
            using assertLiteralEffect[of "state" "hd ?clause'" "False"]
            by (auto simp add: Let_def)
          thus ?thesis
            using assms
            unfolding InvariantQCharacterization_def
            by simp
        next
          case False
          with (getConflictFlag state)  (getQ state) = []
          have "getQ state = []"
            by simp
          thus ?thesis
            using InvariantQCharacterizationAfterAssertLiteralNotInQ[of "state" "hd ?clause'" "False"]
            using assms
            using ‹uniq (elements (getM ?state'))
            using ‹consistent (elements (getM ?state'))
            unfolding InvariantConsistent_def
            unfolding InvariantUniq_def
            using assertLiteralEffect[of "state" "hd ?clause'" "False"]
            by (auto simp add: Let_def)
        qed
        moreover
        have"InvariantUniqQ (getQ ?state')"
          using assms
          using InvariantUniqQAfterAssertLiteral[of "state" "hd ?clause'" "False"]
          by (simp add: Let_def)
        moreover
        have "currentLevel (getM ?state') = 0"
          using assms
          using ¬ clauseTrue ?clause' (elements (getM state))
          using ¬ ?clause' = []
          using assertLiteralEffect[of "state" "hd ?clause'" "False"]
          unfolding addClause_def
          unfolding currentLevel_def
          by (simp add:Let_def markedElementsAppend)
        moreover
        have "var (hd ?clause')  vars F0"
          using ?clause'  []
          using hd_in_set[of "?clause'"]
          using ‹vars ?clause'  vars F0
          using clauseContainsItsLiteralsVariable[of "hd ?clause'" "?clause'"]
          by auto
        hence "InvariantVarsM (getM ?state') F0 Vbl"
          "InvariantVarsQ (getQ ?state') F0 Vbl"
          "InvariantVarsF (getF ?state') F0 Vbl"
          using ‹InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)
          using ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)
          using ‹InvariantWatchListsUniq (getWatchList state)
          using ‹InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)
          using ‹InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)
          using ‹InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)
          using ‹InvariantVarsF (getF state) F0 Vbl
          using ‹InvariantVarsM (getM state) F0 Vbl
          using ‹InvariantVarsQ (getQ state) F0 Vbl
          using ‹consistent (elements (getM ?state'))
          using ‹uniq (elements (getM ?state'))
          using assertLiteralEffect[of "state" "hd ?clause'" "False"]
          using varsAppendValuation[of "elements (getM state)" "[hd ?clause']"]
          using InvariantVarsQAfterAssertLiteral[of "state" "hd ?clause'" "False" "F0" "Vbl"]
          unfolding InvariantVarsM_def
          unfolding InvariantConsistent_def
          unfolding InvariantUniq_def
          by (auto simp add: Let_def)
        moreover
        have "exhaustiveUnitPropagate_dom ?state'"
          using exhaustiveUnitPropagateTermination[of "?state'" "F0" "Vbl"]
          using ‹InvariantUniqQ (getQ ?state')
          using ‹InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state') (getF ?state')
          using ‹InvariantWatchListsUniq (getWatchList ?state')
          using ‹InvariantWatchListsCharacterization (getWatchList ?state') (getWatch1 ?state') (getWatch2 ?state')
          using ‹InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state')
          using ‹InvariantWatchesDiffer (getF ?state') (getWatch1 ?state') (getWatch2 ?state')
          using ‹InvariantQCharacterization (getConflictFlag ?state') (getQ ?state') (getF ?state') (getM ?state')
          using ‹InvariantWatchCharacterization (getF ?state') (getWatch1 ?state') (getWatch2 ?state') (getM ?state')
          using ‹InvariantConflictFlagCharacterization (getConflictFlag ?state') (getF ?state') (getM ?state')
          using ‹consistent (elements (getM ?state'))
          using ‹uniq (elements (getM ?state'))
          using ‹finite Vbl
          using ‹InvariantVarsM (getM ?state') F0 Vbl
          using ‹InvariantVarsQ (getQ ?state') F0 Vbl
          using ‹InvariantVarsF (getF ?state') F0 Vbl
          unfolding InvariantConsistent_def
          unfolding InvariantUniq_def
          by simp
        moreover
        have "¬ clauseTautology clause"
        proof-
          {
            assume "¬ ?thesis"
            then obtain l'
              where "l' el clause" "opposite l' el clause"
              by (auto simp add: clauseTautologyCharacterization)
            have False
            proof (cases "l' el ?clause'")
              case True
              have "opposite l' el ?clause'"
              proof-
                {
                  assume "¬ ?thesis"
                  hence "literalFalse l' (elements (getM state))"
                    using l' el clause
                    using ‹opposite l' el clause
                    using ¬ clauseTrue ?clause' (elements (getM state))
                    using clauseTrueIffContainsTrueLiteral[of "?clause'" "elements (getM state)"]
                    unfolding removeFalseLiterals_def
                    by auto
                  hence False
                    using l' el ?clause'
                    unfolding removeFalseLiterals_def
                    by auto
                } thus ?thesis
                  by auto
              qed
              have " x. x el ?clause'  x = l'"
                using l' el ?clause'
                using ‹length ?clause' = 1
                using lengthOneImpliesOnlyElement[of "?clause'" "l'"]
                by simp
              thus ?thesis
                using ‹opposite l' el ?clause'
                by auto
            next
              case False
              hence "literalFalse l' (elements (getM state))"
                using l' el clause
                unfolding removeFalseLiterals_def
                by simp
              hence "¬ literalFalse (opposite l') (elements (getM state))"
                using ‹InvariantConsistent (getM state)
                unfolding InvariantConsistent_def
                by (auto simp add: inconsistentCharacterization)
              hence "opposite l' el ?clause'"
                using ‹opposite l' el clause
                unfolding removeFalseLiterals_def
                by auto
              thus ?thesis
                using ‹literalFalse l' (elements (getM state))
                using ¬ clauseTrue ?clause' (elements (getM state))
                by (simp add: clauseTrueIffContainsTrueLiteral)
            qed
          } thus ?thesis
            by auto
        qed
        moreover
        note clc = calculation

        show ?thesis
        proof (cases "getSATFlag state = UNDEF")
          case True
          hence "InvariantEquivalentZL (getF state) (getM state) Phi"
            using assms
            by simp
          hence "InvariantEquivalentZL (getF ?state') (getM ?state') (Phi @ [clause])"
            using *
            using falseAndDuplicateLiteralsCanBeRemoved
            [of "getF state" "(elements (prefixToLevel 0 (getM state)))" "[]" "Phi" "clause"]
            using [hd ?clause'] = ?clause'
            using ‹getM state = prefixToLevel 0 (getM state)
            using ‹currentLevel (getM state) = 0
            using prefixToLevelAppend[of "0" "getM state" "[(hd ?clause', False)]"]
            using ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)
            using ‹InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)
            using assertLiteralEffect[of "state" "hd ?clause'" "False"]
            using ‹val2form (elements (getM state)) @ [?clause'] = val2form ((elements (getM state)) @ ?clause')
            using ¬ ?clause' = []
            using ¬ clauseTrue ?clause' (elements (getM state))
            using ‹length ?clause' = 1
            using ‹getSATFlag state = UNDEF›
            unfolding addClause_def
            unfolding InvariantEquivalentZL_def
            by (simp add: Let_def)
          hence "let state'' = addClause clause state in
            InvariantEquivalentZL (getF state'') (getM state'') (Phi @ [clause])  
            getSATFlag state'' = getSATFlag state"
            using clc
            using InvariantEquivalentZLAfterExhaustiveUnitPropagate[of "?state'" "Phi @ [clause]"]
            using exhaustiveUnitPropagatePreservedVariables[of "?state'"]
            using assms
            unfolding InvariantConsistent_def
            unfolding InvariantUniq_def
            using assertLiteralEffect[of "state" "hd ?clause'" "False"]
            by (auto simp only: Let_def)
          thus ?thesis
            using True
            using ¬ clauseTautology clause
            by (auto simp only: Let_def split: if_split) 
        next
          case False
          hence "getSATFlag state = FALSE" "¬ satisfiable Phi"
            using *
            by auto
          hence "getSATFlag ?state' = FALSE"
            using assertLiteralEffect[of "state" "hd ?clause'" "False"]
            using assms
            by simp
          hence "getSATFlag (exhaustiveUnitPropagate ?state') = FALSE" 
            using clc
            using exhaustiveUnitPropagatePreservedVariables[of "?state'"]
            by (auto simp only: Let_def)
          moreover
          have "¬ satisfiable (Phi @ [clause])"
            using satisfiableAppend[of "Phi" "[clause]"]
            using ¬ satisfiable Phi
            by auto
          ultimately
          show ?thesis
            using clc
            using ¬ clauseTautology clause
            by (simp only: Let_def) simp
        qed
      next
        case False
        thus ?thesis
        proof (cases "clauseTautology ?clause'")
          case True
          moreover
          hence "clauseTautology clause"
            unfolding removeFalseLiterals_def
            by (auto simp add: clauseTautologyCharacterization)
          ultimately
          show ?thesis
            using *
            using ¬ ?clause' = []
            using ¬ clauseTrue ?clause' (elements (getM state))
            using ‹length ?clause'  1
            using satisfiableAppend[of "Phi" "[clause]"]
            unfolding addClause_def
            (* Tautology problem *)
            by (auto simp add: Let_def)
        next
          case False
          have "¬ clauseTautology clause"
          proof-
            {
              assume "¬ ?thesis"
              then obtain l' 
                where "l' el clause" "opposite l' el clause"
                by (auto simp add: clauseTautologyCharacterization)
              have False
              proof (cases "l' el ?clause'")
                case True
                hence "¬ opposite l' el ?clause'"
                  using ¬ clauseTautology ?clause'
                  by (auto simp add: clauseTautologyCharacterization)
                hence "literalFalse (opposite l') (elements (getM state))"
                  using ‹opposite l' el clause
                  unfolding removeFalseLiterals_def
                  by auto
                thus ?thesis
                  using ¬ clauseTrue ?clause' (elements (getM state))
                  using l' el ?clause'
                  by (simp add: clauseTrueIffContainsTrueLiteral)
              next
                case False
                hence "literalFalse l' (elements (getM state))"
                  using l' el clause
                  unfolding removeFalseLiterals_def
                  by auto
                hence "¬ literalFalse (opposite l') (elements (getM state))"
                  using ‹InvariantConsistent (getM state)
                  unfolding InvariantConsistent_def
                  by (auto simp add: inconsistentCharacterization)
                hence "opposite l' el ?clause'"
                  using ‹opposite l' el clause
                  unfolding removeFalseLiterals_def
                  by auto
                thus ?thesis
                  using ¬ clauseTrue ?clause' (elements (getM state))
                  using ‹literalFalse l' (elements (getM state))
                  by (simp add: clauseTrueIffContainsTrueLiteral)
              qed
            } thus ?thesis
              by auto
          qed
          show ?thesis
          proof (cases "getSATFlag state = UNDEF")
            case True
            show ?thesis
              using *
              using falseAndDuplicateLiteralsCanBeRemoved
              [of "getF state" "(elements (prefixToLevel 0 (getM state)))" "[]" "Phi" "clause"]
              using ‹getM state = prefixToLevel 0 (getM state)
              using ¬ ?clause' = []
              using ¬ clauseTrue ?clause' (elements (getM state))
              using ‹length ?clause'  1
              using ¬ clauseTautology ?clause'
              using ¬ clauseTautology clause
              using ‹getSATFlag state = UNDEF›
              unfolding addClause_def
              unfolding InvariantEquivalentZL_def
              unfolding setWatch1_def
              unfolding setWatch2_def
              using clauseOrderIrrelevant[of "getF state" "[?clause']" "val2form (elements (getM state))" "[]"]
              using equivalentFormulaeTransitivity[of 
                "getF state @ remdups (removeFalseLiterals clause (elements (getM state))) # val2form (elements (getM state))" 
                "getF state @ val2form (elements (getM state)) @ [remdups (removeFalseLiterals clause (elements (getM state)))]"
                "Phi @ [clause]"]
              by (auto simp add: Let_def)
          next
            case False
            thus ?thesis
              using *
              using satisfiableAppend[of "Phi" "[clause]"]
              using ¬ clauseTrue ?clause' (elements (getM state))
              using ‹length ?clause'  1
              using ¬ clauseTautology ?clause'
              using ¬ clauseTautology clause
              unfolding addClause_def
              unfolding setWatch1_def
              unfolding setWatch2_def
              by (auto simp add: Let_def)
          qed
        qed
      qed
    qed
  qed
qed

(*********************************************************************************)
(*    I N I T I A L I Z E                                                        *)
(*********************************************************************************)

lemma InvariantsAfterInitializationStep:
fixes
  state :: State and Phi :: Formula and Vbl::"Variable set"
assumes
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)"
  "InvariantConflictClauseCharacterization (getConflictFlag state) (getConflictClause state) (getF state) (getM state)"
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"
  "InvariantGetReasonIsReason (getReason state) (getF state) (getM state) (set (getQ state))"
  "InvariantUniqQ (getQ state)"
  "(getConflictFlag state)  (getQ state) = []"
  "currentLevel (getM state) = 0"
  "finite Vbl"
  "InvariantVarsM (getM state) F0 Vbl"
  "InvariantVarsQ (getQ state) F0 Vbl"
  "InvariantVarsF (getF state) F0 Vbl"
  "state' = initialize Phi state"
  "set Phi  set F0"
shows
  "InvariantConsistent (getM state')  
   InvariantUniq (getM state')  
   InvariantWatchListsContainOnlyClausesFromF (getWatchList state') (getF state')  
   InvariantWatchListsUniq (getWatchList state')  
   InvariantWatchListsCharacterization (getWatchList state') (getWatch1 state') (getWatch2 state')  
   InvariantWatchesEl (getF state') (getWatch1 state') (getWatch2 state')  
   InvariantWatchesDiffer (getF state') (getWatch1 state') (getWatch2 state')  
   InvariantWatchCharacterization (getF state') (getWatch1 state') (getWatch2 state') (getM state')  
   InvariantConflictFlagCharacterization (getConflictFlag state') (getF state') (getM state')  
   InvariantConflictClauseCharacterization (getConflictFlag state') (getConflictClause state') (getF state') (getM state')  
   InvariantQCharacterization (getConflictFlag state') (getQ state') (getF state') (getM state')  
   InvariantUniqQ (getQ state')  
   InvariantGetReasonIsReason (getReason state') (getF state') (getM state') (set (getQ state'))  
   InvariantVarsM (getM state') F0 Vbl  
   InvariantVarsQ (getQ state') F0 Vbl  
   InvariantVarsF (getF state') F0 Vbl  
   ((getConflictFlag state')  (getQ state') = [])  
   currentLevel (getM state') = 0" (is "?Inv state'")
using assms
proof (induct Phi arbitrary: state)
  case Nil
  thus ?case
    by simp
next
  case (Cons clause Phi')
  let ?state' = "addClause clause state"
  have "?Inv ?state'"
    using Cons
    using InvariantsAfterAddClause[of "state" "F0" "Vbl" "clause"]
    using formulaContainsItsClausesVariables[of "clause" "F0"]
    by (simp add: Let_def)
  thus ?case
    using Cons(1)[of "?state'"] ‹finite Vbl Cons(18) Cons(19) Cons(20) Cons(21) Cons(22)
    by (simp add: Let_def)
qed

lemma InvariantEquivalentZLAfterInitializationStep:
fixes Phi :: Formula
assumes
  "(getSATFlag state = UNDEF  InvariantEquivalentZL (getF state) (getM state) (filter (λ c. ¬ clauseTautology c) Phi))  
   (getSATFlag state = FALSE  ¬ satisfiable (filter (λ c. ¬ clauseTautology c) Phi))"
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)"
  "InvariantConflictClauseCharacterization (getConflictFlag state) (getConflictClause state) (getF state) (getM state)"
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"
  "InvariantNoDecisionsWhenConflict (getF state) (getM state) (currentLevel (getM state))"
  "InvariantNoDecisionsWhenUnit (getF state) (getM state) (currentLevel (getM state))"
  "InvariantGetReasonIsReason (getReason state) (getF state) (getM state) (set (getQ state))"
  "InvariantUniqQ (getQ state)"
  "finite Vbl"
  "InvariantVarsM (getM state) F0 Vbl"
  "InvariantVarsQ (getQ state) F0 Vbl"
  "InvariantVarsF (getF state) F0 Vbl"
  "(getConflictFlag state)  (getQ state) = []"
  "currentLevel (getM state) = 0"
  "F0 = Phi @ Phi'"
shows
  "let state' = initialize Phi' state in
     (getSATFlag state' = UNDEF  InvariantEquivalentZL (getF state') (getM state') (filter (λ c. ¬ clauseTautology c) F0))  
     (getSATFlag state' = FALSE  ¬satisfiable (filter (λ c. ¬ clauseTautology c) F0))"
using assms
proof (induct Phi' arbitrary: state Phi)
  case Nil
  thus ?case
    unfolding prefixToLevel_def equivalentFormulae_def
    by simp
next
  case (Cons clause Phi'')
  let ?filt = "λ F. (filter (λ c. ¬ clauseTautology c) F)"
  let ?state' = "addClause clause state"
  let ?Phi' = "?filt Phi @ [clause]"
  let ?Phi'' = "if clauseTautology clause then ?filt Phi else ?Phi'"
  from Cons
  have "getSATFlag ?state' = UNDEF  InvariantEquivalentZL (getF ?state') (getM ?state') (?filt ?Phi'')  
        getSATFlag ?state' = FALSE  ¬ satisfiable (?filt ?Phi'')"
    using formulaContainsItsClausesVariables[of "clause" "F0"]
    using InvariantEquivalentZLAfterAddClause[of "state" "?filt Phi" "F0" "Vbl" "clause"]
    by (simp add:Let_def)
  hence "getSATFlag ?state' = UNDEF  InvariantEquivalentZL (getF ?state') (getM ?state') (?filt (Phi @ [clause])) 
         getSATFlag ?state' = FALSE  ¬ satisfiable (?filt (Phi @ [clause]))"
    by auto
  moreover
  from Cons
  have "InvariantConsistent (getM ?state')  
   InvariantUniq (getM ?state')  
   InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state') (getF ?state')  
   InvariantWatchListsUniq (getWatchList ?state')  
   InvariantWatchListsCharacterization (getWatchList ?state') (getWatch1 ?state') (getWatch2 ?state')  
   InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state')  
   InvariantWatchesDiffer (getF ?state') (getWatch1 ?state') (getWatch2 ?state')  
   InvariantWatchCharacterization (getF ?state') (getWatch1 ?state') (getWatch2 ?state') (getM ?state')  
   InvariantConflictFlagCharacterization (getConflictFlag ?state') (getF ?state') (getM ?state')  
   InvariantConflictClauseCharacterization (getConflictFlag ?state') (getConflictClause ?state') (getF ?state') (getM ?state')  
   InvariantQCharacterization (getConflictFlag ?state') (getQ ?state') (getF ?state') (getM ?state')  
   InvariantGetReasonIsReason (getReason ?state') (getF ?state') (getM ?state') (set (getQ ?state'))  
   InvariantUniqQ (getQ ?state')  
   InvariantVarsM (getM ?state') F0 Vbl  
   InvariantVarsQ (getQ ?state') F0 Vbl  
   InvariantVarsF (getF ?state') F0 Vbl  
   ((getConflictFlag ?state')  (getQ ?state') = [])  
   currentLevel (getM ?state') = 0"
    using formulaContainsItsClausesVariables[of "clause" "F0"]
    using InvariantsAfterAddClause
    by (simp add: Let_def)
  moreover
  hence "InvariantNoDecisionsWhenConflict (getF ?state') (getM ?state') (currentLevel (getM ?state'))"
    "InvariantNoDecisionsWhenUnit (getF ?state') (getM ?state') (currentLevel (getM ?state'))"
    unfolding InvariantNoDecisionsWhenConflict_def
    unfolding InvariantNoDecisionsWhenUnit_def
    by auto
  ultimately
  show ?case
    using Cons(1)[of "?state'" "Phi @ [clause]"] ‹finite Vbl Cons(23) Cons(24)
    by (simp add: Let_def)
qed

lemma InvariantsAfterInitialization:
shows
  "let state' = (initialize F0 initialState) in
       InvariantConsistent (getM state')  
       InvariantUniq (getM state')  
       InvariantWatchListsContainOnlyClausesFromF (getWatchList state') (getF state')  
       InvariantWatchListsUniq (getWatchList state')  
       InvariantWatchListsCharacterization (getWatchList state') (getWatch1 state') (getWatch2 state')  
       InvariantWatchesEl (getF state') (getWatch1 state') (getWatch2 state')  
       InvariantWatchesDiffer (getF state') (getWatch1 state') (getWatch2 state')  
       InvariantWatchCharacterization (getF state') (getWatch1 state') (getWatch2 state') (getM state')  
       InvariantConflictFlagCharacterization (getConflictFlag state') (getF state') (getM state')  
       InvariantConflictClauseCharacterization (getConflictFlag state') (getConflictClause state') (getF state') (getM state')  
       InvariantQCharacterization (getConflictFlag state') (getQ state') (getF state') (getM state')  
       InvariantNoDecisionsWhenConflict (getF state') (getM state') (currentLevel (getM state'))  
       InvariantNoDecisionsWhenUnit (getF state') (getM state') (currentLevel (getM state'))  
       InvariantGetReasonIsReason (getReason state') (getF state') (getM state') (set (getQ state'))  
       InvariantUniqQ (getQ state')  
       InvariantVarsM (getM state') F0 {}  
       InvariantVarsQ (getQ state') F0 {}  
       InvariantVarsF (getF state') F0 {}  
       ((getConflictFlag state')  (getQ state') = [])  
       currentLevel (getM state') = 0"
using InvariantsAfterInitializationStep[of "initialState" "{}" "F0" "initialize F0 initialState" "F0"]
unfolding initialState_def
unfolding InvariantConsistent_def
unfolding InvariantUniq_def
unfolding InvariantWatchListsContainOnlyClausesFromF_def
unfolding InvariantWatchListsUniq_def
unfolding InvariantWatchListsCharacterization_def
unfolding InvariantWatchesEl_def
unfolding InvariantWatchesDiffer_def
unfolding InvariantWatchCharacterization_def
unfolding watchCharacterizationCondition_def
unfolding InvariantConflictFlagCharacterization_def
unfolding InvariantConflictClauseCharacterization_def
unfolding InvariantQCharacterization_def
unfolding InvariantUniqQ_def
unfolding InvariantNoDecisionsWhenConflict_def
unfolding InvariantNoDecisionsWhenUnit_def
unfolding InvariantGetReasonIsReason_def
unfolding InvariantVarsM_def
unfolding InvariantVarsQ_def
unfolding InvariantVarsF_def
unfolding currentLevel_def
by (simp) (force)

lemma InvariantEquivalentZLAfterInitialization:
fixes F0 :: Formula
shows
  "let state' = (initialize F0 initialState) in
   let F0' = (filter (λ c. ¬ clauseTautology c) F0) in
     (getSATFlag state' = UNDEF  InvariantEquivalentZL (getF state') (getM state') F0')  
     (getSATFlag state' = FALSE  ¬ satisfiable F0')"
using InvariantEquivalentZLAfterInitializationStep[of "initialState" "[]" "{}" "F0" "F0"]
unfolding initialState_def
unfolding InvariantEquivalentZL_def
unfolding InvariantConsistent_def
unfolding InvariantUniq_def
unfolding InvariantWatchesEl_def
unfolding InvariantWatchesDiffer_def
unfolding InvariantWatchListsContainOnlyClausesFromF_def
unfolding InvariantWatchListsUniq_def
unfolding InvariantWatchListsCharacterization_def
unfolding InvariantWatchCharacterization_def
unfolding InvariantConflictFlagCharacterization_def
unfolding InvariantConflictClauseCharacterization_def
unfolding InvariantQCharacterization_def
unfolding InvariantNoDecisionsWhenConflict_def
unfolding InvariantNoDecisionsWhenUnit_def
unfolding InvariantGetReasonIsReason_def
unfolding InvariantVarsM_def
unfolding InvariantVarsQ_def
unfolding InvariantVarsF_def
unfolding watchCharacterizationCondition_def
unfolding InvariantUniqQ_def
unfolding prefixToLevel_def
unfolding equivalentFormulae_def
unfolding currentLevel_def
by (auto simp add: Let_def)

end

Theory ConflictAnalysis

theory ConflictAnalysis
imports AssertLiteral
begin

(******************************************************************************)
(*           A P P L Y    C O N F L I C T                                     *)
(******************************************************************************)

lemma clauseFalseInPrefixToLastAssertedLiteral:
  assumes 
  "isLastAssertedLiteral l (oppositeLiteralList c) (elements M)" and
  "clauseFalse c (elements M)" and 
  "uniq (elements M)"
  shows "clauseFalse c (elements (prefixToLevel (elementLevel l M) M))"
proof-
  {
    fix l'::Literal
    assume "l' el c"
    hence "literalFalse l' (elements M)"
      using ‹clauseFalse c (elements M)
      by (simp add: clauseFalseIffAllLiteralsAreFalse)
    hence "literalTrue (opposite l') (elements M)"
      by simp

    have "opposite l' el oppositeLiteralList c"
      using l' el c
      using literalElListIffOppositeLiteralElOppositeLiteralList[of "l'" "c"]
      by simp

    have "elementLevel (opposite l') M  elementLevel l M"
      using lastAssertedLiteralHasHighestElementLevel[of "l" "oppositeLiteralList c" "M"]
      using ‹isLastAssertedLiteral l (oppositeLiteralList c) (elements M)
      using ‹uniq (elements M)
      using ‹opposite l' el oppositeLiteralList c
      using ‹literalTrue (opposite l') (elements M)
      by auto
    hence "opposite l' el (elements (prefixToLevel (elementLevel l M) M))"
      using elementLevelLtLevelImpliesMemberPrefixToLevel[of "opposite l'" "M" "elementLevel l M"]
      using ‹literalTrue (opposite l') (elements M)
      by simp
  } thus ?thesis
    by (simp add: clauseFalseIffAllLiteralsAreFalse)
qed
  

lemma InvariantNoDecisionsWhenConflictEnsuresCurrentLevelCl:
assumes 
  "InvariantNoDecisionsWhenConflict F M (currentLevel M)"
  "clause el F"
  "clauseFalse clause (elements M)"
  "uniq (elements M)"
  "currentLevel M > 0"
shows
  "clause  []  
   (let Cl = getLastAssertedLiteral (oppositeLiteralList clause) (elements M) in 
           InvariantClCurrentLevel Cl M)"
proof-
  have "clause  []"
  proof-
    { 
      assume "¬ ?thesis"
      hence "clauseFalse clause (elements (prefixToLevel ((currentLevel M) - 1) M))"
        by simp
      hence False
        using ‹InvariantNoDecisionsWhenConflict F M (currentLevel M)
        using ‹currentLevel M > 0
        using clause el F
        unfolding InvariantNoDecisionsWhenConflict_def
        by (simp add: formulaFalseIffContainsFalseClause)
    } thus ?thesis
      by auto
  qed
  moreover
  let ?Cl = "getLastAssertedLiteral (oppositeLiteralList clause) (elements M)"
  have "elementLevel ?Cl M = currentLevel M"
  proof-
    have "elementLevel ?Cl M  currentLevel M"
      using elementLevelLeqCurrentLevel[of "?Cl" "M"]
      by simp
    moreover
    have "elementLevel ?Cl M  currentLevel M"
    proof-
      {
        assume "elementLevel ?Cl M < currentLevel M"
        have "isLastAssertedLiteral ?Cl (oppositeLiteralList clause) (elements M)"
          using getLastAssertedLiteralCharacterization[of "clause" "elements M"]
          using ‹uniq (elements M)
          using ‹clauseFalse clause (elements M)
          using clause  []
          by simp
        hence "clauseFalse clause (elements (prefixToLevel (elementLevel ?Cl M) M))"
          using clauseFalseInPrefixToLastAssertedLiteral[of "?Cl" "clause" "M"]
          using ‹clauseFalse clause (elements M)
          using ‹uniq (elements M)
          by simp
        hence "False"
          using clause el F
          using ‹InvariantNoDecisionsWhenConflict F M (currentLevel M)
          using ‹currentLevel M > 0
          unfolding InvariantNoDecisionsWhenConflict_def
          using ‹elementLevel ?Cl M < currentLevel M
          by (simp add: formulaFalseIffContainsFalseClause)
      } thus ?thesis
        by force
    qed
    ultimately
    show ?thesis
      by simp
  qed
  ultimately
  show ?thesis
    unfolding InvariantClCurrentLevel_def
    by (simp add: Let_def)
qed

lemma InvariantsClAfterApplyConflict:
assumes
  "getConflictFlag state"
  "InvariantUniq (getM state)"
  "InvariantNoDecisionsWhenConflict (getF state) (getM state) (currentLevel (getM state))"
  "InvariantEquivalentZL (getF state) (getM state) F0"
  "InvariantConflictClauseCharacterization (getConflictFlag state) (getConflictClause state) (getF state) (getM state)"
  "currentLevel (getM state) > 0"
shows
  "let state' = applyConflict state in 
          InvariantCFalse (getConflictFlag state') (getM state') (getC state')  
          InvariantCEntailed (getConflictFlag state') F0 (getC state')  
          InvariantClCharacterization (getCl state') (getC state') (getM state')  
          InvariantClCurrentLevel (getCl state') (getM state')  
          InvariantCnCharacterization (getCn state') (getC state') (getM state')  
          InvariantUniqC (getC state')"
proof-
  let ?M0 = "elements (prefixToLevel 0 (getM state))"
  let ?oppM0 = "oppositeLiteralList ?M0"

  let ?clause' = "nth (getF state) (getConflictClause state)"
  let ?clause'' = "list_diff ?clause' ?oppM0"
  let ?clause = "remdups ?clause''"
  let ?l = "getLastAssertedLiteral (oppositeLiteralList ?clause') (elements (getM state))"

  have "clauseFalse ?clause' (elements (getM state))" "?clause' el (getF state)"
    using ‹getConflictFlag state
    using ‹InvariantConflictClauseCharacterization (getConflictFlag state) (getConflictClause state) (getF state) (getM state)
    unfolding InvariantConflictClauseCharacterization_def
    by (auto simp add: Let_def)

  have "?clause'  []" "elementLevel ?l (getM state) = currentLevel (getM state)"
    using InvariantNoDecisionsWhenConflictEnsuresCurrentLevelCl[of "getF state" "getM state" "?clause'"]
    using ?clause' el (getF state)
    using ‹clauseFalse ?clause' (elements (getM state))
    using ‹InvariantNoDecisionsWhenConflict (getF state) (getM state) (currentLevel (getM state))
    using ‹currentLevel (getM state) > 0
    using ‹InvariantUniq (getM state)
    unfolding InvariantUniq_def
    unfolding InvariantClCurrentLevel_def
    by (auto simp add: Let_def)


  have "isLastAssertedLiteral ?l (oppositeLiteralList ?clause') (elements (getM state))"
    using ?clause'  []
    using ‹clauseFalse ?clause' (elements (getM state))
    using ‹InvariantUniq (getM state)
    unfolding InvariantUniq_def
    using getLastAssertedLiteralCharacterization[of "?clause'" "elements (getM state)"]
    by simp
  hence "?l el (oppositeLiteralList ?clause')"
    unfolding isLastAssertedLiteral_def
    by simp
  hence "opposite ?l el ?clause'"
    using literalElListIffOppositeLiteralElOppositeLiteralList[of "opposite ?l" "?clause'"]
    by auto

  have "¬ ?l el ?M0"
  proof-
    {
      assume "¬ ?thesis"
      hence "elementLevel ?l (getM state) = 0"
        using prefixToLevelElementsElementLevel[of "?l" "0" "getM state"]
        by simp
      hence False
        using ‹elementLevel ?l (getM state) = currentLevel (getM state)
        using ‹currentLevel (getM state) > 0
        by simp
    }
    thus ?thesis
      by auto
  qed

  hence "¬ opposite ?l el ?oppM0"
    using literalElListIffOppositeLiteralElOppositeLiteralList[of "?l" "elements (prefixToLevel 0 (getM state))"]
    by simp

  have "opposite ?l el ?clause''"
    using ‹opposite ?l el ?clause'
    using ¬ opposite ?l el ?oppM0
    using listDiffIff[of "opposite ?l" "?clause'" "?oppM0"]
    by simp
  hence "?l el (oppositeLiteralList ?clause'')"
    using literalElListIffOppositeLiteralElOppositeLiteralList[of "opposite ?l" "?clause''"]
    by simp

  have "set (oppositeLiteralList ?clause'')  set (oppositeLiteralList ?clause')"
  proof
    fix x
    assume "x  set (oppositeLiteralList ?clause'')"
    thus "x  set (oppositeLiteralList ?clause')"
      using literalElListIffOppositeLiteralElOppositeLiteralList[of "opposite x" "?clause''"]
      using literalElListIffOppositeLiteralElOppositeLiteralList[of "opposite x" "?clause'"]
      using listDiffIff[of "opposite x" "?clause'" "oppositeLiteralList (elements (prefixToLevel 0 (getM state)))"]
      by auto
  qed

  have "isLastAssertedLiteral ?l (oppositeLiteralList ?clause'') (elements (getM state))"
    using ?l el (oppositeLiteralList ?clause'')
    using ‹set (oppositeLiteralList ?clause'')  set (oppositeLiteralList ?clause')
    using ‹isLastAssertedLiteral ?l (oppositeLiteralList ?clause') (elements (getM state))
    using isLastAssertedLiteralSubset[of "?l" "oppositeLiteralList ?clause'" "elements (getM state)" "oppositeLiteralList ?clause''"]
    by auto
  moreover
  have "set (oppositeLiteralList ?clause) = set (oppositeLiteralList ?clause'')"
    unfolding oppositeLiteralList_def
    by simp
  ultimately
  have "isLastAssertedLiteral ?l (oppositeLiteralList ?clause) (elements (getM state))"
    unfolding isLastAssertedLiteral_def
    by auto

  hence "?l el (oppositeLiteralList ?clause)"
    unfolding isLastAssertedLiteral_def
    by simp
  hence "opposite ?l el ?clause"
    using literalElListIffOppositeLiteralElOppositeLiteralList[of "opposite ?l" "?clause"]
    by simp
  hence "?clause  []"
    by auto

  have "clauseFalse ?clause'' (elements (getM state))"
  proof-
    {
      fix l::Literal
      assume "l el ?clause''"
      hence "l el ?clause'"
        using listDiffIff[of "l" "?clause'" "?oppM0"]
        by simp
      hence "literalFalse l (elements (getM state))"
        using ‹clauseFalse ?clause' (elements (getM state))
        by (simp add: clauseFalseIffAllLiteralsAreFalse)
    }
    thus ?thesis
      by (simp add: clauseFalseIffAllLiteralsAreFalse)
  qed
  hence "clauseFalse ?clause (elements (getM state))"
    by (simp add: clauseFalseIffAllLiteralsAreFalse)

  let ?l' = "getLastAssertedLiteral (oppositeLiteralList ?clause) (elements (getM state))"
  have "isLastAssertedLiteral ?l' (oppositeLiteralList ?clause) (elements (getM state))"
    using ?clause  []
    using ‹clauseFalse ?clause (elements (getM state))
    using ‹InvariantUniq (getM state)
    unfolding InvariantUniq_def
    using getLastAssertedLiteralCharacterization[of "?clause" "elements (getM state)"]
    by simp
  with ‹isLastAssertedLiteral ?l (oppositeLiteralList ?clause) (elements (getM state))
  have "?l = ?l'"
    using lastAssertedLiteralIsUniq
    by simp

  have "formulaEntailsClause (getF state) ?clause'"
    using ?clause' el (getF state)
    by (simp add: formulaEntailsItsClauses)

  let ?F0 = "(getF state) @ val2form ?M0"

  have "formulaEntailsClause ?F0 ?clause'"
    using ‹formulaEntailsClause (getF state) ?clause'
    by (simp add: formulaEntailsClauseAppend)
  
  hence "formulaEntailsClause ?F0 ?clause''"
    using ‹formulaEntailsClause (getF state) ?clause'
    using formulaEntailsClauseRemoveEntailedLiteralOpposites[of "?F0" "?clause'" "?M0"]
    using val2formIsEntailed[of "getF state" "?M0" "[]"]
    by simp
  hence "formulaEntailsClause ?F0 ?clause"
    unfolding formulaEntailsClause_def
    by (simp add: clauseTrueIffContainsTrueLiteral)

  hence "formulaEntailsClause F0 ?clause"
    using ‹InvariantEquivalentZL (getF state) (getM state) F0
    unfolding InvariantEquivalentZL_def
    unfolding formulaEntailsClause_def
    unfolding equivalentFormulae_def
    by auto
  
  show ?thesis
    using ‹isLastAssertedLiteral ?l' (oppositeLiteralList ?clause) (elements (getM state))
    using ?l = ?l'
    using ‹elementLevel ?l (getM state) = currentLevel (getM state)
    using ‹clauseFalse ?clause (elements (getM state))
    using ‹formulaEntailsClause F0 ?clause
    unfolding applyConflict_def
    unfolding setConflictAnalysisClause_def
    unfolding InvariantClCharacterization_def
    unfolding InvariantClCurrentLevel_def
    unfolding InvariantCFalse_def
    unfolding InvariantCEntailed_def
    unfolding InvariantCnCharacterization_def
    unfolding InvariantUniqC_def
    by (auto simp add: findLastAssertedLiteral_def countCurrentLevelLiterals_def Let_def uniqDistinct distinct_remdups_id)
qed

(******************************************************************************)
(*           A P P L Y    E X P L A I N                                       *)
(******************************************************************************)

lemma CnEqual1IffUIP:
assumes
"InvariantClCharacterization (getCl state) (getC state) (getM state)"
"InvariantClCurrentLevel (getCl state) (getM state)"
"InvariantCnCharacterization (getCn state) (getC state) (getM state)"
shows
"(getCn state = 1) = isUIP (opposite (getCl state)) (getC state) (getM state)"
proof-
  let ?clls = "filter  (λ l. elementLevel (opposite l) (getM state) = currentLevel (getM state)) (remdups (getC state))"
  let ?Cl = "getCl state"

  have "isLastAssertedLiteral ?Cl (oppositeLiteralList (getC state)) (elements (getM state))"
    using ‹InvariantClCharacterization (getCl state) (getC state) (getM state)
    unfolding InvariantClCharacterization_def
    .
  hence "literalTrue ?Cl (elements (getM state))" "?Cl el (oppositeLiteralList (getC state))"
    unfolding isLastAssertedLiteral_def
    by auto
  hence "opposite ?Cl el getC state"
    using literalElListIffOppositeLiteralElOppositeLiteralList[of "opposite ?Cl" "getC state"]
    by simp
  
  hence "opposite ?Cl el ?clls"
    using ‹InvariantClCurrentLevel (getCl state) (getM state)
    unfolding InvariantClCurrentLevel_def
    by auto
  hence "?clls  []"
    by force
  hence "length ?clls > 0"
    by simp

  have "uniq ?clls"
    by (simp add: uniqDistinct)

  {
    assume "getCn state  1"
    hence "length ?clls > 1"
      using assms
      using ‹length ?clls > 0
      unfolding InvariantCnCharacterization_def
      by (simp (no_asm))
    then obtain literal1::Literal and literal2::Literal
      where "literal1 el ?clls" "literal2 el ?clls" "literal1  literal2"
      using ‹uniq ?clls
      using ?clls  []
      using lengthGtOneTwoDistinctElements[of "?clls"]
      by auto
    then obtain literal::Literal
      where "literal el ?clls" "literal  opposite ?Cl"
      using ‹opposite ?Cl el ?clls
      by auto
    hence "¬ isUIP (opposite ?Cl) (getC state) (getM state)"
      using ‹opposite ?Cl el ?clls
      unfolding isUIP_def
      by auto
  }
  moreover
  {
    assume "getCn state = 1"
    hence "length ?clls = 1"
      using ‹InvariantCnCharacterization (getCn state) (getC state) (getM state)
      unfolding InvariantCnCharacterization_def
      by auto
    {
      fix literal::Literal
      assume "literal el (getC state)" "literal  opposite ?Cl"
      have "elementLevel (opposite literal) (getM state) < currentLevel (getM state)"
      proof-
        have "elementLevel (opposite literal) (getM state)  currentLevel (getM state)"
          using elementLevelLeqCurrentLevel[of "opposite literal" "getM state"]
          by simp
        moreover
        have "elementLevel (opposite literal) (getM state)  currentLevel (getM state)"
        proof-
          {
            assume "¬ ?thesis"
            with literal el (getC state)
            have "literal el ?clls"
              by simp
            hence "False"
              using ‹length ?clls = 1
              using ‹opposite ?Cl el ?clls
              using literal  opposite ?Cl
              using lengthOneImpliesOnlyElement[of "?clls" "opposite ?Cl"]
              by auto
          }
          thus ?thesis
            by auto
        qed
        ultimately
        show ?thesis
          by simp
      qed
    }
    hence "isUIP (opposite ?Cl) (getC state) (getM state)"
      using ‹isLastAssertedLiteral ?Cl (oppositeLiteralList (getC state)) (elements (getM state))
      using ‹opposite ?Cl el ?clls
      unfolding isUIP_def
      by auto
  }
  ultimately
  show ?thesis
    by auto
qed


lemma InvariantsClAfterApplyExplain:
assumes
  "InvariantUniq (getM state)"
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)"
  "InvariantClCharacterization (getCl state) (getC state) (getM state)"
  "InvariantClCurrentLevel (getCl state) (getM state)"
  "InvariantCEntailed (getConflictFlag state) F0 (getC state)"
  "InvariantCnCharacterization (getCn state) (getC state) (getM state)"
  "InvariantEquivalentZL (getF state) (getM state) F0"
  "InvariantGetReasonIsReason (getReason state) (getF state) (getM state) (set (getQ state))"
  "getCn state  1"
  "getConflictFlag state"
  "currentLevel (getM state) > 0"
shows
  "let state' = applyExplain (getCl state) state in 
      InvariantCFalse (getConflictFlag state') (getM state') (getC state')  
      InvariantCEntailed (getConflictFlag state') F0 (getC state')  
      InvariantClCharacterization (getCl state') (getC state') (getM state')  
      InvariantClCurrentLevel (getCl state') (getM state')  
      InvariantCnCharacterization (getCn state') (getC state') (getM state')  
      InvariantUniqC (getC state')"
proof-
  let ?Cl = "getCl state"
  let ?oppM0 = "oppositeLiteralList (elements (prefixToLevel 0 (getM state)))"

  have "isLastAssertedLiteral ?Cl (oppositeLiteralList (getC state)) (elements (getM state))"
    using ‹InvariantClCharacterization (getCl state) (getC state) (getM state)
    unfolding InvariantClCharacterization_def
    .
  hence "literalTrue ?Cl (elements (getM state))" "?Cl el (oppositeLiteralList (getC state))"
    unfolding isLastAssertedLiteral_def
    by auto
  hence "opposite ?Cl el getC state"
    using literalElListIffOppositeLiteralElOppositeLiteralList[of "opposite ?Cl" "getC state"]
    by simp


  have "clauseFalse (getC state) (elements (getM state))"
    using ‹getConflictFlag state
    using ‹InvariantCFalse (getConflictFlag state) (getM state) (getC state)
    unfolding InvariantCFalse_def
    by simp

  have "¬ isUIP (opposite ?Cl) (getC state) (getM state)"
    using CnEqual1IffUIP[of "state"]
    using assms
    by simp
    

  have "¬ ?Cl el (decisions (getM state))"
  proof-
    {
      assume "¬ ?thesis"
      hence "isUIP (opposite ?Cl) (getC state) (getM state)"
        using ‹InvariantUniq (getM state)
        using ‹isLastAssertedLiteral ?Cl (oppositeLiteralList (getC state)) (elements (getM state))
        using ‹clauseFalse (getC state) (elements (getM state))
        using lastDecisionThenUIP[of "getM state" "opposite ?Cl" "getC state"]
        unfolding InvariantUniq_def
        by simp
      with ¬ isUIP (opposite ?Cl) (getC state) (getM state)
      have "False"
        by simp
    } thus ?thesis
      by auto
  qed

  have "elementLevel ?Cl (getM state) = currentLevel (getM state)"
    using ‹InvariantClCurrentLevel (getCl state) (getM state)
    unfolding InvariantClCurrentLevel_def
    by simp
  hence "elementLevel ?Cl (getM state) > 0"
    using ‹currentLevel (getM state) > 0
    by simp

  obtain reason
    where "isReason (nth (getF state) reason) ?Cl (elements (getM state))"
    "getReason state ?Cl = Some reason" "0  reason  reason < length (getF state)"
    using ‹InvariantGetReasonIsReason (getReason state) (getF state) (getM state) (set (getQ state))
    unfolding InvariantGetReasonIsReason_def
    using ‹literalTrue ?Cl (elements (getM state))
    using ¬ ?Cl el (decisions (getM state))
    using ‹elementLevel ?Cl (getM state) > 0
    by auto

  let ?res = "resolve (getC state) (getF state ! reason) (opposite ?Cl)"

  obtain ol::Literal
    where "ol el (getC state)" 
          "ol  opposite ?Cl" 
          "elementLevel (opposite ol) (getM state)  elementLevel ?Cl (getM state)"
    using ‹isLastAssertedLiteral ?Cl (oppositeLiteralList (getC state)) (elements (getM state))
    using ¬ isUIP (opposite ?Cl) (getC state) (getM state)
    unfolding isUIP_def
    by auto
  hence "ol el ?res"
    unfolding resolve_def
    by simp
  hence "?res  []"
    by auto
  have "opposite ol el (oppositeLiteralList ?res)"
    using ol el ?res
    using literalElListIffOppositeLiteralElOppositeLiteralList[of "ol" "?res"]
    by simp

  have "opposite ol el (oppositeLiteralList (getC state))"
    using ol el (getC state)
    using literalElListIffOppositeLiteralElOppositeLiteralList[of "ol" "getC state"]
    by simp

  have "literalFalse ol (elements (getM state))"
    using ‹clauseFalse (getC state) (elements (getM state))
    using ol el getC state
    by (simp add: clauseFalseIffAllLiteralsAreFalse)

  have "elementLevel (opposite ol) (getM state) = elementLevel ?Cl (getM state)"
    using ‹elementLevel (opposite ol) (getM state)  elementLevel ?Cl (getM state)
    using ‹isLastAssertedLiteral ?Cl (oppositeLiteralList (getC state)) (elements (getM state))
    using lastAssertedLiteralHasHighestElementLevel[of "?Cl" "oppositeLiteralList (getC state)" "getM state"]
    using ‹InvariantUniq (getM state)
    unfolding InvariantUniq_def
    using ‹opposite ol el (oppositeLiteralList (getC state))
    using ‹literalFalse ol (elements (getM state))
    by auto
  hence "elementLevel (opposite ol) (getM state) = currentLevel (getM state)"
    using ‹elementLevel ?Cl (getM state) = currentLevel (getM state)
    by simp
  
  have "InvariantCFalse (getConflictFlag state) (getM state) ?res"
    using ‹InvariantCFalse (getConflictFlag state) (getM state) (getC state)
    using InvariantCFalseAfterExplain[of "getConflictFlag state" 
      "getM state" "getC state" "?Cl" "nth (getF state) reason" "?res"]
    using ‹isReason (nth (getF state) reason) ?Cl (elements (getM state))
    using ‹opposite ?Cl el (getC state)
    by simp
  hence "clauseFalse ?res (elements (getM state))"
    using ‹getConflictFlag state
    unfolding InvariantCFalse_def
    by simp

  let ?rc = "nth (getF state) reason"
  let ?M0 = "elements (prefixToLevel 0 (getM state))"
  let ?F0 = "(getF state) @ (val2form ?M0)"
  let ?C' = "list_diff ?res ?oppM0"
  let ?C = "remdups ?C'"
  
  have "formulaEntailsClause (getF state) ?rc"
    using 0  reason  reason < length (getF state)
    using nth_mem[of "reason" "getF state"]
    by (simp add: formulaEntailsItsClauses)
  hence "formulaEntailsClause ?F0 ?rc"
    by (simp add: formulaEntailsClauseAppend)

  hence "formulaEntailsClause F0 ?rc"
    using ‹InvariantEquivalentZL (getF state) (getM state) F0
    unfolding InvariantEquivalentZL_def
    unfolding formulaEntailsClause_def
    unfolding equivalentFormulae_def
    by simp

  hence "formulaEntailsClause F0 ?res"
    using ‹getConflictFlag state
    using ‹InvariantCEntailed (getConflictFlag state) F0 (getC state)
    using InvariantCEntailedAfterExplain[of "getConflictFlag state" "F0" "getC state" "nth (getF state) reason" "?res" "getCl state"]
    unfolding InvariantCEntailed_def
    by auto
  hence "formulaEntailsClause ?F0 ?res"
    using ‹InvariantEquivalentZL (getF state) (getM state) F0
    unfolding InvariantEquivalentZL_def
    unfolding formulaEntailsClause_def
    unfolding equivalentFormulae_def
    by simp
    
  hence "formulaEntailsClause ?F0 ?C"
    using formulaEntailsClauseRemoveEntailedLiteralOpposites[of "?F0" "?res" "?M0"]
    using val2formIsEntailed[of "getF state" "?M0" "[]"]
    unfolding formulaEntailsClause_def
    by (auto simp add: clauseTrueIffContainsTrueLiteral)

  hence "formulaEntailsClause F0 ?C"
    using ‹InvariantEquivalentZL (getF state) (getM state) F0
    unfolding InvariantEquivalentZL_def
    unfolding formulaEntailsClause_def
    unfolding equivalentFormulae_def
    by simp

  let ?ll = "getLastAssertedLiteral (oppositeLiteralList ?res) (elements (getM state))"
  have "isLastAssertedLiteral ?ll (oppositeLiteralList ?res) (elements (getM state))"
    using ?res  []
    using ‹clauseFalse ?res (elements (getM state))
    using ‹InvariantUniq (getM state)
    unfolding InvariantUniq_def
    using getLastAssertedLiteralCharacterization[of "?res" "elements (getM state)"]
    by simp

  hence "elementLevel (opposite ol) (getM state)  elementLevel ?ll (getM state)"
    using ‹opposite ol el (oppositeLiteralList (getC state))
    using lastAssertedLiteralHasHighestElementLevel[of "?ll" "oppositeLiteralList ?res" "getM state"]
    using ‹InvariantUniq (getM state)
    using ‹opposite ol el (oppositeLiteralList ?res)
    using ‹literalFalse ol (elements (getM state))
    unfolding InvariantUniq_def
    by simp
  hence "elementLevel ?ll (getM state) = currentLevel (getM state)"
    using ‹elementLevel (opposite ol) (getM state) = currentLevel (getM state)
    using elementLevelLeqCurrentLevel[of "?ll" "getM state"]
    by simp

  have "?ll el (oppositeLiteralList ?res)"
    using ‹isLastAssertedLiteral ?ll (oppositeLiteralList ?res) (elements (getM state))
    unfolding isLastAssertedLiteral_def
    by simp
  hence "opposite ?ll el ?res"
    using literalElListIffOppositeLiteralElOppositeLiteralList[of "opposite ?ll" "?res"]
    by simp

  have "¬ ?ll el (elements (prefixToLevel 0 (getM state)))"
  proof-
    {
      assume "¬ ?thesis"
      hence "elementLevel ?ll (getM state) = 0"
        using prefixToLevelElementsElementLevel[of "?ll" "0" "getM state"]
        by simp
      hence False
        using ‹elementLevel ?ll (getM state) = currentLevel (getM state)
        using ‹currentLevel (getM state) > 0
        by simp
    }
    thus ?thesis
      by auto
  qed
  hence "¬ opposite ?ll el ?oppM0"
    using literalElListIffOppositeLiteralElOppositeLiteralList[of "?ll" "elements (prefixToLevel 0 (getM state))"]
    by simp

  have "opposite ?ll el ?C'"
    using ‹opposite ?ll el ?res
    using ¬ opposite ?ll el ?oppM0
    using listDiffIff[of "opposite ?ll" "?res" "?oppM0"]
    by simp
  hence "?ll el (oppositeLiteralList ?C')"
    using literalElListIffOppositeLiteralElOppositeLiteralList[of "opposite ?ll" "?C'"]
    by simp

  have "set (oppositeLiteralList ?C')  set (oppositeLiteralList ?res)"
  proof
    fix x
    assume "x  set (oppositeLiteralList ?C')"
    thus "x  set (oppositeLiteralList ?res)"
      using literalElListIffOppositeLiteralElOppositeLiteralList[of "opposite x" "?C'"]
      using literalElListIffOppositeLiteralElOppositeLiteralList[of "opposite x" "?res"]
      using listDiffIff[of "opposite x" "?res" "?oppM0"]
      by auto
  qed

  have "isLastAssertedLiteral ?ll (oppositeLiteralList ?C') (elements (getM state))"
    using ?ll el (oppositeLiteralList ?C')
    using ‹set (oppositeLiteralList ?C')  set (oppositeLiteralList ?res)
    using ‹isLastAssertedLiteral ?ll (oppositeLiteralList ?res) (elements (getM state))
    using isLastAssertedLiteralSubset[of "?ll" "oppositeLiteralList ?res" "elements (getM state)" "oppositeLiteralList ?C'"]
    by auto
  moreover
  have "set (oppositeLiteralList ?C) = set (oppositeLiteralList ?C')"
    unfolding oppositeLiteralList_def
    by simp
  ultimately
  have "isLastAssertedLiteral ?ll (oppositeLiteralList ?C) (elements (getM state))"
    unfolding isLastAssertedLiteral_def
    by auto

  hence "?ll el (oppositeLiteralList ?C)"
    unfolding isLastAssertedLiteral_def
    by simp
  hence "opposite ?ll el ?C"
    using literalElListIffOppositeLiteralElOppositeLiteralList[of "opposite ?ll" "?C"]
    by simp
  hence "?C  []"
    by auto

  have "clauseFalse ?C' (elements (getM state))"
  proof-
    {
      fix l::Literal
      assume "l el ?C'"
      hence "l el ?res"
        using listDiffIff[of "l" "?res" "?oppM0"]
        by simp
      hence "literalFalse l (elements (getM state))"
        using ‹clauseFalse ?res (elements (getM state))
        by (simp add: clauseFalseIffAllLiteralsAreFalse)
    }
    thus ?thesis
      by (simp add: clauseFalseIffAllLiteralsAreFalse)
  qed
  hence "clauseFalse ?C (elements (getM state))"
    by (simp add: clauseFalseIffAllLiteralsAreFalse)

  let ?l' = "getLastAssertedLiteral (oppositeLiteralList ?C) (elements (getM state))"
  have "isLastAssertedLiteral ?l' (oppositeLiteralList ?C) (elements (getM state))"
    using ?C  []
    using ‹clauseFalse ?C (elements (getM state))
    using ‹InvariantUniq (getM state)
    unfolding InvariantUniq_def
    using getLastAssertedLiteralCharacterization[of "?C" "elements (getM state)"]
    by simp
  with ‹isLastAssertedLiteral ?ll (oppositeLiteralList ?C) (elements (getM state))
  have "?ll = ?l'"
    using lastAssertedLiteralIsUniq
    by simp

  show ?thesis
    using ‹isLastAssertedLiteral ?l' (oppositeLiteralList ?C) (elements (getM state))
    using ?ll = ?l'
    using ‹elementLevel ?ll (getM state) = currentLevel (getM state)
    using ‹getReason state ?Cl = Some reason
    using ‹clauseFalse ?C (elements (getM state))
    using ‹formulaEntailsClause F0 ?C
    unfolding applyExplain_def
    unfolding InvariantCFalse_def
    unfolding InvariantCEntailed_def
    unfolding InvariantClCharacterization_def
    unfolding InvariantClCurrentLevel_def
    unfolding InvariantCnCharacterization_def
    unfolding InvariantUniqC_def
    unfolding setConflictAnalysisClause_def
    by (simp add: findLastAssertedLiteral_def countCurrentLevelLiterals_def Let_def uniqDistinct distinct_remdups_id)
qed

(******************************************************************************)
(*           A P P L Y    E X P L A I N    U I P                              *)
(******************************************************************************)

definition 
"multLessState = {(state1, state2). (getM state1 = getM state2)  (getC state1, getC state2)  multLess (getM state1)}"

lemma ApplyExplainUIPTermination:
assumes
"InvariantUniq (getM state)"
"InvariantGetReasonIsReason (getReason state) (getF state) (getM state) (set (getQ state))"
"InvariantCFalse (getConflictFlag state) (getM state) (getC state)"
"InvariantClCurrentLevel (getCl state) (getM state)"
"InvariantClCharacterization (getCl state) (getC state) (getM state)"
"InvariantCnCharacterization (getCn state) (getC state) (getM state)"
"InvariantCEntailed (getConflictFlag state) F0 (getC state)"
"InvariantEquivalentZL (getF state) (getM state) F0"
"getConflictFlag state"
"currentLevel (getM state) > 0"
shows
"applyExplainUIP_dom state"
using assms
proof (induct rule: wf_induct[of "multLessState"])
  case 1
  thus ?case
    unfolding wf_eq_minimal
  proof-
    show "Q (state::State). state  Q  ( stateMin  Q. state'. (state', stateMin)  multLessState  state'  Q)"
    proof-
      {
        fix Q :: "State set" and state :: State
        assume "state  Q"
        let ?M = "(getM state)"
        let ?Q1 = "{C::Clause.  state. state  Q  (getM state) = ?M  (getC state) = C}"
        from state  Q 
        have "getC state  ?Q1"
          by auto   
        with wfMultLess[of "?M"]
        obtain Cmin where "Cmin  ?Q1" "C'. (C', Cmin)  multLess ?M  C'  ?Q1"
          unfolding wf_eq_minimal
          apply (erule_tac x="?Q1" in allE)
          apply (erule_tac x="getC state" in allE)
          by auto
        from Cmin  ?Q1 obtain stateMin
          where "stateMin  Q" "(getM stateMin) = ?M" "getC stateMin = Cmin"
          by auto
        have "state'. (state', stateMin)  multLessState  state'  Q"
        proof
          fix state'
          show "(state', stateMin)  multLessState  state'  Q"
          proof
            assume "(state', stateMin)  multLessState"
            with ‹getM stateMin = ?M
            have "getM state' = getM stateMin" "(getC state', getC stateMin)  multLess ?M"
              unfolding multLessState_def
              by auto
            from C'. (C', Cmin)  multLess ?M  C'  ?Q1
              (getC state', getC stateMin)  multLess ?M ‹getC stateMin = Cmin
            have "getC state'  ?Q1"
              by simp
            with ‹getM state' = getM stateMin ‹getM stateMin = ?M
            show "state'  Q"
              by auto
          qed
        qed
        with stateMin  Q 
        have " stateMin  Q. (state'. (state', stateMin)  multLessState  state'  Q)"
          by auto
      }
      thus ?thesis
        by auto
    qed
  qed
next
  case (2 state')
  note ih = this
  show ?case
  proof (cases "getCn state' = 1")
    case True
    show ?thesis
      apply (rule applyExplainUIP_dom.intros)
      using True
      by simp
  next
    case False
    let ?state'' = "applyExplain (getCl state') state'"
    have "InvariantGetReasonIsReason (getReason ?state'') (getF ?state'') (getM ?state'') (set (getQ ?state''))"
      "InvariantUniq (getM ?state'')"
      "InvariantEquivalentZL (getF ?state'') (getM ?state'') F0"
      "getConflictFlag ?state''"
      "currentLevel (getM ?state'') > 0"
      using ih
      unfolding applyExplain_def
      unfolding setConflictAnalysisClause_def
      by (auto split: option.split simp add: findLastAssertedLiteral_def countCurrentLevelLiterals_def Let_def)
    moreover
    have "InvariantCFalse (getConflictFlag ?state'') (getM ?state'') (getC ?state'')"
      "InvariantClCharacterization (getCl ?state'') (getC ?state'') (getM ?state'')"
      "InvariantCnCharacterization (getCn ?state'') (getC ?state'') (getM ?state'')"
      "InvariantClCurrentLevel (getCl ?state'') (getM ?state'')"
      "InvariantCEntailed (getConflictFlag ?state'') F0 (getC ?state'')"
      using InvariantsClAfterApplyExplain[of "state'" "F0"]
      using ih
      using False
      by (auto simp add:Let_def)
    moreover
    have "(?state'', state')  multLessState"
    proof-
      have "getM ?state'' = getM state'"
        unfolding applyExplain_def
        unfolding setConflictAnalysisClause_def
        by (auto split: option.split simp add: findLastAssertedLiteral_def countCurrentLevelLiterals_def Let_def)

      let ?Cl = "getCl state'"
      let ?oppM0 = "oppositeLiteralList (elements (prefixToLevel 0 (getM state')))"

      have "isLastAssertedLiteral ?Cl (oppositeLiteralList (getC state')) (elements (getM state'))"
        using ih
        unfolding InvariantClCharacterization_def
        by simp
      hence "literalTrue ?Cl (elements (getM state'))" "?Cl el (oppositeLiteralList (getC state'))"
        unfolding isLastAssertedLiteral_def
        by auto
      hence "opposite ?Cl el getC state'"
        using literalElListIffOppositeLiteralElOppositeLiteralList[of "opposite ?Cl" "getC state'"]
        by simp

      have "clauseFalse (getC state') (elements (getM state'))"
        using ih
        unfolding InvariantCFalse_def
        by simp

      have "¬ ?Cl el (decisions (getM state'))"
      proof-
        {
          assume "¬ ?thesis"
          hence "isUIP (opposite ?Cl) (getC state') (getM state')"
            using ih 
            using ‹isLastAssertedLiteral ?Cl (oppositeLiteralList (getC state')) (elements (getM state'))
            using ‹clauseFalse (getC state') (elements (getM state'))
            using lastDecisionThenUIP[of "getM state'" "opposite ?Cl" "getC state'"]
            unfolding InvariantUniq_def
            unfolding isUIP_def
            by simp
          with ‹getCn state'  1
          have "False"
            using CnEqual1IffUIP[of "state'"]
            using ih
            by simp
        } thus ?thesis
          by auto
      qed

      have "elementLevel ?Cl (getM state') = currentLevel (getM state')"
        using ih
        unfolding InvariantClCurrentLevel_def
        by simp
      hence "elementLevel ?Cl (getM state') > 0"
        using ih
        by simp

      obtain reason
        where "isReason (nth (getF state') reason) ?Cl (elements (getM state'))"
        "getReason state' ?Cl = Some reason" "0  reason  reason < length (getF state')"
        using ih
        unfolding InvariantGetReasonIsReason_def
        using ‹literalTrue ?Cl (elements (getM state'))
        using ¬ ?Cl el (decisions (getM state'))
        using ‹elementLevel ?Cl (getM state') > 0
        by auto

      let ?res = "resolve (getC state') (getF state' ! reason) (opposite ?Cl)"

      have "getC ?state'' = (remdups (list_diff ?res ?oppM0))"
        unfolding applyExplain_def
        unfolding setConflictAnalysisClause_def
        using ‹getReason state' ?Cl = Some reason
        by (simp add: Let_def findLastAssertedLiteral_def countCurrentLevelLiterals_def)

      have "(?res, getC state')  multLess (getM state')"
        using multLessResolve[of "?Cl" "getC state'" "nth (getF state') reason" "getM state'"]
        using ‹opposite ?Cl el (getC state')
        using ‹isReason (nth (getF state') reason) ?Cl (elements (getM state'))
        by simp
      hence "(list_diff ?res ?oppM0, getC state')  multLess (getM state')"
        by (simp add: multLessListDiff)

      have "(remdups (list_diff ?res ?oppM0), getC state')  multLess (getM state')"
        using (list_diff ?res ?oppM0, getC state')  multLess (getM state')
        by (simp add: multLessRemdups)
      thus ?thesis
        using ‹getC ?state'' = (remdups (list_diff ?res ?oppM0))
        using ‹getM ?state'' = getM state'
        unfolding multLessState_def
        by simp
    qed
    ultimately
    have "applyExplainUIP_dom ?state''"
      using ih
      by auto
    thus ?thesis
      using applyExplainUIP_dom.intros[of "state'"]
      using False
      by simp
  qed
qed
  

lemma ApplyExplainUIPPreservedVariables:
assumes
  "applyExplainUIP_dom state"
shows
  "let state' = applyExplainUIP state in 
        (getM state' = getM state) 
        (getF state' = getF state) 
        (getQ state' = getQ state) 
        (getWatch1 state' = getWatch1 state) 
        (getWatch2 state' = getWatch2 state) 
        (getWatchList state' = getWatchList state) 
        (getConflictFlag state' = getConflictFlag state)  
        (getConflictClause state' = getConflictClause state)  
        (getSATFlag state' = getSATFlag state)  
        (getReason state' = getReason state)" 
  (is "let state' = applyExplainUIP state in ?p state state'")
using assms
proof(induct state rule: applyExplainUIP_dom.induct)
  case (step state')
  note ih = this
  show ?case
  proof (cases "getCn state' = 1")
    case True
    with applyExplainUIP.simps[of "state'"]
    have "applyExplainUIP state' = state'"
      by simp
    thus ?thesis
      by (auto simp only: Let_def)
  next
    case False
    let ?state' = "applyExplainUIP (applyExplain (getCl state') state')"
    from applyExplainUIP.simps[of "state'"] False
    have "applyExplainUIP state' = ?state'"
      by (simp add: Let_def)
    have "?p state' (applyExplain (getCl state') state')"
      unfolding applyExplain_def
      unfolding setConflictAnalysisClause_def
      by (auto split: option.split simp add: findLastAssertedLiteral_def countCurrentLevelLiterals_def Let_def)
    thus ?thesis
      using ih
      using False
      using ‹applyExplainUIP state' = ?state'
      by (simp add: Let_def)
  qed
qed

lemma isUIPApplyExplainUIP:
  assumes "applyExplainUIP_dom state"
  "InvariantUniq (getM state)"
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)"
  "InvariantCEntailed (getConflictFlag state) F0 (getC state)"
  "InvariantClCharacterization (getCl state) (getC state) (getM state)"
  "InvariantCnCharacterization (getCn state) (getC state) (getM state)"
  "InvariantClCurrentLevel (getCl state) (getM state)"
  "InvariantGetReasonIsReason (getReason state) (getF state) (getM state) (set (getQ state))"
  "InvariantEquivalentZL (getF state) (getM state) F0"
  "getConflictFlag state"
  "currentLevel (getM state) > 0"
  shows "let state' = (applyExplainUIP state) in
           isUIP (opposite (getCl state')) (getC state') (getM state')"
using assms
proof(induct state rule: applyExplainUIP_dom.induct)
  case (step state')
  note ih = this
  show ?case
  proof (cases "getCn state' = 1")
    case True
    with applyExplainUIP.simps[of "state'"]
    have "applyExplainUIP state' = state'"
      by simp
    thus ?thesis
      using ih
      using CnEqual1IffUIP[of "state'"]
      using True
      by (simp add: Let_def)
  next
    case False
    let ?state'' = "applyExplain (getCl state') state'"
    let ?state' = "applyExplainUIP ?state''"
    from applyExplainUIP.simps[of "state'"] False
    have "applyExplainUIP state' = ?state'"
      by (simp add: Let_def)
    moreover
    have "InvariantUniq (getM ?state'')"
      "InvariantGetReasonIsReason (getReason ?state'') (getF ?state'') (getM ?state'') (set (getQ ?state''))"
      "InvariantEquivalentZL (getF ?state'') (getM ?state'') F0"
      "getConflictFlag ?state''"
      "currentLevel (getM ?state'') > 0"
      using ih
      unfolding applyExplain_def
      unfolding setConflictAnalysisClause_def
      by (auto split: option.split simp add: findLastAssertedLiteral_def countCurrentLevelLiterals_def Let_def)
    moreover
    have "InvariantCFalse (getConflictFlag ?state'') (getM ?state'') (getC ?state'')"
      "InvariantCEntailed (getConflictFlag ?state'') F0 (getC ?state'')"
      "InvariantClCharacterization (getCl ?state'') (getC ?state'') (getM ?state'')"
      "InvariantCnCharacterization (getCn ?state'') (getC ?state'') (getM ?state'')"
      "InvariantClCurrentLevel (getCl ?state'') (getM ?state'')"
      using False
      using ih
      using InvariantsClAfterApplyExplain[of "state'" "F0"]
      by (auto simp add: Let_def)
    ultimately
    show ?thesis
      using ih(2)
      using False
      by (simp add: Let_def)
  qed
qed


lemma InvariantsClAfterExplainUIP:
assumes
  "applyExplainUIP_dom state"
  "InvariantUniq (getM state)"
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)"
  "InvariantCEntailed (getConflictFlag state) F0 (getC state)"
  "InvariantClCharacterization (getCl state) (getC state) (getM state)"
  "InvariantCnCharacterization (getCn state) (getC state) (getM state)"
  "InvariantClCurrentLevel (getCl state) (getM state)"
  "InvariantUniqC (getC state)"
  "InvariantGetReasonIsReason (getReason state) (getF state) (getM state) (set (getQ state))"
  "InvariantEquivalentZL (getF state) (getM state) F0"
  "getConflictFlag state"
  "currentLevel (getM state) > 0"
shows
  "let state' = applyExplainUIP state in 
      InvariantCFalse (getConflictFlag state') (getM state') (getC state')  
      InvariantCEntailed (getConflictFlag state') F0 (getC state')  
      InvariantClCharacterization (getCl state') (getC state') (getM state')  
      InvariantCnCharacterization (getCn state') (getC state') (getM state')  
      InvariantClCurrentLevel (getCl state') (getM state')  
      InvariantUniqC (getC state')"
using assms
proof(induct state rule: applyExplainUIP_dom.induct)
  case (step state')
  note ih = this
  show ?case
  proof (cases "getCn state' = 1")
    case True
    with applyExplainUIP.simps[of "state'"]
    have "applyExplainUIP state' = state'"
      by simp
    thus ?thesis
      using assms
      using ih
      by (auto simp only: Let_def)
  next
    case False
    let ?state'' = "applyExplain (getCl state') state'"
    let ?state' = "applyExplainUIP ?state''"
    from applyExplainUIP.simps[of "state'"] False
    have "applyExplainUIP state' = ?state'"
      by (simp add: Let_def)
    moreover
    have "InvariantUniq (getM ?state'')"
      "InvariantGetReasonIsReason (getReason ?state'') (getF ?state'') (getM ?state'') (set (getQ ?state''))"
      "InvariantEquivalentZL (getF ?state'') (getM ?state'') F0"
      "getConflictFlag ?state''"
      "currentLevel (getM ?state'') > 0"
      using ih
      unfolding applyExplain_def
      unfolding setConflictAnalysisClause_def
      by (auto split: option.split simp add: findLastAssertedLiteral_def countCurrentLevelLiterals_def Let_def)
    moreover
    have "InvariantCFalse (getConflictFlag ?state'') (getM ?state'') (getC ?state'')"
      "InvariantCEntailed (getConflictFlag ?state'') F0 (getC ?state'')"
      "InvariantClCharacterization (getCl ?state'') (getC ?state'') (getM ?state'')"
      "InvariantCnCharacterization (getCn ?state'') (getC ?state'') (getM ?state'')"
      "InvariantClCurrentLevel (getCl ?state'') (getM ?state'')"
      "InvariantUniqC (getC ?state'')"
      using False
      using ih
      using InvariantsClAfterApplyExplain[of "state'" "F0"]
      by (auto simp add: Let_def)
    ultimately
    show ?thesis
      using False
      using ih(2)
      by simp
  qed
qed

(******************************************************************************)
(*           G E T     B A C K J U M P   L E V E L                            *)
(******************************************************************************)

lemma oneElementSetCharacterization:
shows 
"(set l = {a}) = ((remdups l) = [a])"
proof (induct l)
  case Nil
  thus ?case
    by simp
next
  case (Cons a' l')
  show ?case
  proof (cases "l' = []")
    case True
    thus ?thesis
      by simp
  next
    case False
    then obtain b
      where "b  set l'"
      by force
    show ?thesis
    proof
      assume "set (a' # l') = {a}"
      hence "a' = a" "set l'  {a}"
        by auto
      hence "b = a"
        using b  set l'
        by auto
      hence "{a}  set l'"
        using b  set l'
        by auto
      hence "set l' = {a}"
        using ‹set l'  {a}
        by auto
      thus "remdups (a' # l') = [a]"
        using a' = a
        using Cons
        by simp
    next
      assume "remdups (a' # l') = [a]"
      thus "set (a' # l') = {a}"
        using set_remdups[of "a' # l'"]
        by auto
    qed
  qed
qed

lemma uniqOneElementCharacterization:
assumes
  "uniq l"
shows
  "(l = [a]) = (set l = {a})"
using assms
using uniqDistinct[of "l"]
using oneElementSetCharacterization[of "l" "a"]
using distinct_remdups_id[of "l"]
by auto

lemma isMinimalBackjumpLevelGetBackjumpLevel: 
assumes
  "InvariantUniq (getM state)"
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)"
  "InvariantClCharacterization (getCl state) (getC state) (getM state)"
  "InvariantCllCharacterization (getCl state) (getCll state) (getC state) (getM state)"
  "InvariantClCurrentLevel (getCl state) (getM state)"
  "InvariantUniqC (getC state)"

  "getConflictFlag state"
  "isUIP (opposite (getCl state)) (getC state) (getM state)"
  "currentLevel (getM state) > 0"
shows
  "isMinimalBackjumpLevel (getBackjumpLevel state) (opposite (getCl state)) (getC state) (getM state)"
proof-
  let ?oppC = "oppositeLiteralList (getC state)"
  let ?Cl = "getCl state"
    
  have "isLastAssertedLiteral ?Cl ?oppC (elements (getM state))"
    using ‹InvariantClCharacterization (getCl state) (getC state) (getM state)
    unfolding InvariantClCharacterization_def
    by simp

  have "elementLevel ?Cl (getM state) > 0"
    using ‹InvariantClCurrentLevel (getCl state) (getM state)
    using ‹currentLevel (getM state) > 0
    unfolding InvariantClCurrentLevel_def
    by simp

  have "clauseFalse (getC state) (elements (getM state))"
    using ‹getConflictFlag state
    using ‹InvariantCFalse (getConflictFlag state) (getM state) (getC state)
    unfolding InvariantCFalse_def
    by simp

  show ?thesis
  proof (cases "getC state = [opposite ?Cl]")
    case True
    thus ?thesis
      using backjumpLevelZero[of "opposite ?Cl" "oppositeLiteralList ?oppC" "getM state"]
      using ‹isLastAssertedLiteral ?Cl ?oppC (elements (getM state))
      using True
      using ‹elementLevel ?Cl (getM state) > 0
      unfolding getBackjumpLevel_def
      unfolding isMinimalBackjumpLevel_def
      by (simp add: Let_def)
  next
    let ?Cll = "getCll state" 
    case False
    with ‹InvariantCllCharacterization (getCl state) (getCll state) (getC state) (getM state)
    ‹InvariantUniqC (getC state)
    have "isLastAssertedLiteral ?Cll (removeAll ?Cl ?oppC) (elements (getM state))"
      unfolding InvariantCllCharacterization_def
      unfolding InvariantUniqC_def
      using uniqOneElementCharacterization[of "getC state" "opposite ?Cl"]
      by simp
    hence "?Cll el ?oppC" "?Cll  ?Cl"
      unfolding isLastAssertedLiteral_def
      by auto
    hence "opposite ?Cll el (getC state)"
      using literalElListIffOppositeLiteralElOppositeLiteralList[of "?Cll" "?oppC"]
      by auto

    show ?thesis
      using backjumpLevelLastLast[of "opposite ?Cl" "getC state" "getM state" "opposite ?Cll"]
      using ‹isUIP (opposite (getCl state)) (getC state) (getM state)
      using ‹clauseFalse (getC state) (elements (getM state))
      using ‹isLastAssertedLiteral ?Cll (removeAll ?Cl ?oppC) (elements (getM state))
      using ‹InvariantUniq (getM state)
      using ‹InvariantUniqC (getC state)
      using uniqOneElementCharacterization[of "getC state" "opposite ?Cl"]
      unfolding InvariantUniqC_def
      unfolding InvariantUniq_def
      using False
      using ‹opposite ?Cll el (getC state)
      unfolding getBackjumpLevel_def
      unfolding isMinimalBackjumpLevel_def
      by (auto simp add: Let_def)
  qed
qed


(******************************************************************************)
(*           A P P L Y    L E A R N                                           *)
(******************************************************************************)

lemma applyLearnPreservedVariables:
"let state' = applyLearn state in 
    getM state' = getM state  
    getQ state' = getQ state  
    getC state' = getC state  
    getCl state' = getCl state 
    getConflictFlag state' = getConflictFlag state  
    getConflictClause state' = getConflictClause state  
    getF state' = (if getC state = [opposite (getCl state)] then 
                               getF state 
                     else 
                            (getF state @ [getC state])
                    )"
proof (cases "getC state = [opposite (getCl state)]")
  case True
  thus ?thesis
    unfolding applyLearn_def
    unfolding setWatch1_def
    unfolding setWatch2_def
    by (simp add:Let_def)
next
  case False
  thus ?thesis
    unfolding applyLearn_def
    unfolding setWatch1_def
    unfolding setWatch2_def
    by (simp add:Let_def)
qed

lemma WatchInvariantsAfterApplyLearn:
assumes
  "InvariantUniq (getM state)" and
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)" and 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)" and
  "InvariantClCharacterization (getCl state) (getC state) (getM state)" and

  "getConflictFlag state"
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)"
  "InvariantUniqC (getC state)"
shows
  "let state' = (applyLearn state) in
     InvariantWatchesEl (getF state') (getWatch1 state') (getWatch2 state')  
     InvariantWatchesDiffer (getF state') (getWatch1 state') (getWatch2 state')  
     InvariantWatchCharacterization (getF state') (getWatch1 state') (getWatch2 state') (getM state')  
     InvariantWatchListsContainOnlyClausesFromF (getWatchList state') (getF state')  
     InvariantWatchListsUniq (getWatchList state')  
     InvariantWatchListsCharacterization (getWatchList state') (getWatch1 state') (getWatch2 state')"
proof (cases "getC state  [opposite (getCl state)]")
  case False
  thus ?thesis
    using assms
    unfolding applyLearn_def
    unfolding InvariantCllCharacterization_def
    by (simp add: Let_def)
next
  case True

  let ?oppC = "oppositeLiteralList (getC state)"
  let ?l = "getCl state"
  let ?ll = "getLastAssertedLiteral (removeAll ?l ?oppC) (elements (getM state))"

  have "clauseFalse (getC state) (elements (getM state))"
    using ‹getConflictFlag state
    using ‹InvariantCFalse (getConflictFlag state) (getM state) (getC state)
    unfolding InvariantCFalse_def
    by simp


  from True
  have "set (getC state)  {opposite ?l}"
    using ‹InvariantUniqC (getC state)
    using uniqOneElementCharacterization[of "getC state" "opposite ?l"]
    unfolding InvariantUniqC_def
    by (simp add: Let_def)

  
  have "isLastAssertedLiteral ?l ?oppC (elements (getM state))"
    using ‹InvariantClCharacterization (getCl state) (getC state) (getM state)
    unfolding InvariantClCharacterization_def
    by simp

  have "opposite ?l el (getC state)"
    using ‹isLastAssertedLiteral ?l ?oppC (elements (getM state))
    unfolding isLastAssertedLiteral_def
    using literalElListIffOppositeLiteralElOppositeLiteralList[of "?l" "?oppC"]
    by simp

  have "removeAll ?l ?oppC  []"
  proof-
    { 
      assume "¬ ?thesis"
      hence "set ?oppC  {?l}"
        using set_removeAll[of "?l" "?oppC"]
        by auto
      have "set (getC state)  {opposite ?l}"
      proof
        fix x
        assume "x  set (getC state)"
        hence "opposite x  set ?oppC"
          using literalElListIffOppositeLiteralElOppositeLiteralList[of "x" "getC state"]
          by simp
        hence "opposite x  {?l}"
          using ‹set ?oppC  {?l}
          by auto
        thus "x  {opposite ?l}"
          using oppositeSymmetry[of "x" "?l"]
          by force
      qed
      hence False
        using ‹set (getC state)  {opposite ?l}
        using ‹opposite ?l el getC state
        by (auto simp add: Let_def)
    } thus ?thesis
      by auto
  qed

  have "clauseFalse (oppositeLiteralList (removeAll ?l ?oppC)) (elements (getM state))"
    using ‹clauseFalse (getC state) (elements (getM state))
    using oppositeLiteralListRemove[of "?l" "?oppC"]
    by (simp add: clauseFalseIffAllLiteralsAreFalse)
  moreover 
  have "oppositeLiteralList (removeAll ?l ?oppC)  []"
    using ‹removeAll ?l ?oppC  []
    using oppositeLiteralListNonempty
    by simp
  ultimately
  have "isLastAssertedLiteral ?ll (removeAll ?l ?oppC) (elements (getM state))"
    using ‹InvariantUniq (getM state)
    unfolding InvariantUniq_def
    using getLastAssertedLiteralCharacterization[of "oppositeLiteralList (removeAll ?l ?oppC)" "elements (getM state)"]
    by auto
  hence "?ll el (removeAll ?l ?oppC)"
    unfolding isLastAssertedLiteral_def
    by auto
  hence "?ll el ?oppC" "?ll  ?l"
    by auto 
  hence "opposite ?ll el (getC state)"
    using literalElListIffOppositeLiteralElOppositeLiteralList[of "?ll" "?oppC"]
    by auto

  let ?state' = "applyLearn state"

  have "InvariantWatchesEl (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
  proof-
    {
      fix clause::nat
      assume "0  clause  clause < length (getF ?state')"
      have  "w1 w2. getWatch1 ?state' clause = Some w1 
                     getWatch2 ?state' clause = Some w2 
                     w1 el (getF ?state' ! clause)  w2 el (getF ?state' ! clause)"
      proof (cases "clause < length (getF state)")
        case True
        thus ?thesis
          using ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)
          unfolding InvariantWatchesEl_def
          using ‹set (getC state)  {opposite ?l}
          unfolding applyLearn_def
          unfolding setWatch1_def
          unfolding setWatch2_def
          by (auto simp add:Let_def nth_append)
      next
        case False
        with  0  clause  clause < length (getF ?state')
        have "clause = length (getF state)"
          using ‹getC state  [opposite ?l]
          unfolding applyLearn_def
          unfolding setWatch1_def
          unfolding setWatch2_def
          by (auto simp add: Let_def)
        moreover
        have "getWatch1 ?state' clause = Some (opposite ?l)" "getWatch2 ?state' clause = Some (opposite ?ll)"
          using clause = length (getF state)
          using ‹set (getC state)  {opposite ?l}
          unfolding applyLearn_def
          unfolding setWatch1_def
          unfolding setWatch2_def
          by (auto simp add: Let_def)
        moreover
        have "getF ?state' ! clause = (getC state)"
          using clause = length (getF state)
          using ‹set (getC state)  {opposite ?l}
          unfolding applyLearn_def
          unfolding setWatch1_def
          unfolding setWatch2_def
          by (auto simp add: Let_def)
        ultimately
        show ?thesis
          using ‹opposite ?l el (getC state) ‹opposite ?ll el (getC state)
          by force
      qed
    } thus ?thesis
      unfolding InvariantWatchesEl_def
      by auto
  qed
  moreover
  have "InvariantWatchesDiffer (getF ?state') (getWatch1 ?state') (getWatch2 ?state')"
  proof-
    {
      fix clause::nat
      assume "0  clause  clause < length (getF ?state')"
      have  "getWatch1 ?state' clause  getWatch2 ?state' clause"
      proof (cases "clause < length (getF state)")
        case True
        thus ?thesis
          using ‹InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)
          unfolding InvariantWatchesDiffer_def
          using ‹set (getC state)  {opposite ?l}
          unfolding applyLearn_def
          unfolding setWatch1_def
          unfolding setWatch2_def
          by (auto simp add:Let_def nth_append)
      next
        case False
        with  0  clause  clause < length (getF ?state')
        have "clause = length (getF state)"
          using ‹getC state  [opposite ?l]
          unfolding applyLearn_def
          unfolding setWatch1_def
          unfolding setWatch2_def
          by (auto simp add: Let_def)
        moreover
        have "getWatch1 ?state' clause = Some (opposite ?l)" "getWatch2 ?state' clause = Some (opposite ?ll)"
          using clause = length (getF state)
          using ‹set (getC state)  {opposite ?l}
          unfolding applyLearn_def
          unfolding setWatch1_def
          unfolding setWatch2_def
          by (auto simp add: Let_def)
        moreover
        have "getF ?state' ! clause = (getC state)"
          using clause = length (getF state)
          using ‹set (getC state)  {opposite ?l}
          unfolding applyLearn_def
          unfolding setWatch1_def
          unfolding setWatch2_def
          by (auto simp add: Let_def)
        ultimately
        show ?thesis
          using ?ll  ?l
          by force
      qed
    } thus ?thesis
      unfolding InvariantWatchesDiffer_def
      by auto
  qed
  moreover
  have "InvariantWatchCharacterization (getF ?state') (getWatch1 ?state') (getWatch2 ?state') (getM ?state')"
  proof-
    {
      fix clause::nat and w1::Literal and w2::Literal
      assume *: "0  clause  clause < length (getF ?state')"
      assume **: "Some w1 = getWatch1 ?state' clause" "Some w2 = getWatch2 ?state' clause"
      have "watchCharacterizationCondition w1 w2 (getM ?state') (getF ?state' ! clause)  
            watchCharacterizationCondition w2 w1 (getM ?state') (getF ?state' ! clause)"
      proof (cases "clause < length (getF state)")
        case True
        thus ?thesis
          using ‹InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)
          unfolding InvariantWatchCharacterization_def
          using ‹set (getC state)  {opposite ?l}
          using **
          unfolding applyLearn_def
          unfolding setWatch1_def
          unfolding setWatch2_def
          by (auto simp add:Let_def nth_append)
      next
        case False
        with  0  clause  clause < length (getF ?state')
        have "clause = length (getF state)"
          using ‹getC state  [opposite ?l]
          unfolding applyLearn_def
          unfolding setWatch1_def
          unfolding setWatch2_def
          by (auto simp add: Let_def)
        moreover
        have "getWatch1 ?state' clause = Some (opposite ?l)" "getWatch2 ?state' clause = Some (opposite ?ll)"
          using clause = length (getF state)
          using ‹set (getC state)  {opposite ?l}
          unfolding applyLearn_def
          unfolding setWatch1_def
          unfolding setWatch2_def
          by (auto simp add: Let_def)
        moreover
        have " l. l el (getC state)  l  opposite ?l  l  opposite ?ll  
                   elementLevel (opposite l) (getM state)  elementLevel ?l (getM state)  
                   elementLevel (opposite l) (getM state)  elementLevel ?ll (getM state)"
        proof-
          { 
            fix l
            assume "l el (getC state)" "l  opposite ?l" "l  opposite ?ll"
            hence "opposite l el ?oppC" 
              using literalElListIffOppositeLiteralElOppositeLiteralList[of "l" "getC state"]
              by simp
            moreover
            from l  opposite ?l
            have "opposite l  ?l"
              using oppositeSymmetry[of "l" "?l"]
              by blast
            ultimately
            have "opposite l el (removeAll ?l ?oppC)"
              by simp
              
            from ‹clauseFalse (getC state) (elements (getM state))
            have "literalFalse l (elements (getM state))"
              using l el (getC state)
              by (simp add: clauseFalseIffAllLiteralsAreFalse)
            hence "elementLevel (opposite l) (getM state)  elementLevel ?l (getM state)  
              elementLevel (opposite l) (getM state)  elementLevel ?ll (getM state)"
              using ‹InvariantUniq (getM state)
              unfolding InvariantUniq_def
              using ‹isLastAssertedLiteral ?l ?oppC (elements (getM state))
              using lastAssertedLiteralHasHighestElementLevel[of "?l" "?oppC" "getM state"]
              using ‹isLastAssertedLiteral ?ll (removeAll ?l ?oppC) (elements (getM state))
              using lastAssertedLiteralHasHighestElementLevel[of "?ll" "(removeAll ?l ?oppC)" "getM state"]
              using ‹opposite l el ?oppC ‹opposite l el (removeAll ?l ?oppC)
              by simp
          }
          thus ?thesis
            by simp
        qed
        moreover
        have "getF ?state' ! clause = (getC state)"
          using clause = length (getF state)
          using ‹set (getC state)  {opposite ?l}
          unfolding applyLearn_def
          unfolding setWatch1_def
          unfolding setWatch2_def
          by (auto simp add: Let_def)
        moreover
        have "getM ?state' = getM state"
          using ‹set (getC state)  {opposite ?l}
          unfolding applyLearn_def
          unfolding setWatch1_def
          unfolding setWatch2_def
          by (auto simp add: Let_def)
        ultimately
        show ?thesis
          using ‹clauseFalse (getC state) (elements (getM state))
          using **
          unfolding watchCharacterizationCondition_def
          by (auto simp add: clauseFalseIffAllLiteralsAreFalse)
      qed
    } thus ?thesis
      unfolding InvariantWatchCharacterization_def
      by auto
  qed
  moreover
  have "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state') (getF ?state')"
  proof-
    {
      fix clause::nat and literal::Literal
      assume "clause  set (getWatchList ?state' literal)"
      have "clause < length (getF ?state')"
      proof(cases "clause  set (getWatchList state literal)")
        case True
        thus ?thesis
          using ‹InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)
          unfolding InvariantWatchListsContainOnlyClausesFromF_def
          using ‹set (getC state)  {opposite ?l}
          unfolding applyLearn_def
          unfolding setWatch1_def
          unfolding setWatch2_def
          by (auto simp add:Let_def nth_append) (force)+
      next
        case False
        with clause  set (getWatchList ?state' literal)
        have "clause = length (getF state)"
          using ‹set (getC state)  {opposite ?l}
          unfolding applyLearn_def
          unfolding setWatch1_def
          unfolding setWatch2_def
          by (auto simp add:Let_def nth_append split: if_split_asm)
        thus ?thesis
          using ‹set (getC state)  {opposite ?l}
          unfolding applyLearn_def
          unfolding setWatch1_def
          unfolding setWatch2_def
          by (auto simp add:Let_def nth_append)
      qed
    } thus ?thesis
      unfolding InvariantWatchListsContainOnlyClausesFromF_def
      by simp
  qed
  moreover
  have "InvariantWatchListsUniq (getWatchList ?state')"
    unfolding InvariantWatchListsUniq_def
  proof
    fix l::Literal
    show "uniq (getWatchList ?state' l)"
    proof(cases "l = opposite ?l  l = opposite ?ll")
      case True
      hence "getWatchList ?state' l = (length (getF state)) # getWatchList state l"
        using ‹set (getC state)  {opposite ?l}
        unfolding applyLearn_def
        unfolding setWatch1_def
        unfolding setWatch2_def
        using ?ll  ?l
        by (auto simp add:Let_def nth_append)
      moreover
      have "length (getF state)  set (getWatchList state l)"
        using ‹InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)
        unfolding InvariantWatchListsContainOnlyClausesFromF_def
        by auto
      ultimately
      show ?thesis
        using ‹InvariantWatchListsUniq (getWatchList state)
        unfolding InvariantWatchListsUniq_def
        by (simp add: uniqAppendIff)
    next
      case False
      hence "getWatchList ?state' l = getWatchList state l"
        using ‹set (getC state)  {opposite ?l}
        unfolding applyLearn_def
        unfolding setWatch1_def
        unfolding setWatch2_def
        by (auto simp add:Let_def nth_append)
      thus ?thesis
        using ‹InvariantWatchListsUniq (getWatchList state)
        unfolding InvariantWatchListsUniq_def
        by simp
    qed
  qed
  moreover
  have "InvariantWatchListsCharacterization (getWatchList ?state') (getWatch1 ?state') (getWatch2 ?state')"
  proof-
    {
      fix c::nat and l::Literal
      have "(c  set (getWatchList ?state' l)) = (Some l = getWatch1 ?state' c  Some l = getWatch2 ?state' c)"
      proof (cases "c = length (getF state)")
        case False
        thus ?thesis
          using ‹InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)
          unfolding InvariantWatchListsCharacterization_def
          using ‹set (getC state)  {opposite ?l}
          unfolding applyLearn_def
          unfolding setWatch1_def
          unfolding setWatch2_def
          by (auto simp add:Let_def nth_append)
      next
        case True
        have "length (getF state)  set (getWatchList state l)"
          using ‹InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)
          unfolding InvariantWatchListsContainOnlyClausesFromF_def
          by auto
        thus ?thesis
          using c = length (getF state)
        using ‹InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)
        unfolding InvariantWatchListsCharacterization_def
        using ‹set (getC state)  {opposite ?l}
        unfolding applyLearn_def
        unfolding setWatch1_def
        unfolding setWatch2_def
        by (auto simp add:Let_def nth_append)
    qed
  } thus ?thesis
    unfolding InvariantWatchListsCharacterization_def
    by simp
  qed
  moreover
  have "InvariantClCharacterization (getCl ?state') (getC ?state') (getM ?state')"
    using ‹InvariantClCharacterization (getCl state) (getC state) (getM state)
    using ‹set (getC state)  {opposite ?l}
    unfolding applyLearn_def
    unfolding setWatch1_def
    unfolding setWatch2_def
    by (auto simp add:Let_def)
  moreover
  have "InvariantCllCharacterization (getCl ?state') (getCll ?state') (getC ?state') (getM ?state')"
    unfolding InvariantCllCharacterization_def
    using ‹isLastAssertedLiteral ?ll (removeAll ?l ?oppC) (elements (getM state))
    using ‹set (getC state)  {opposite ?l}
    unfolding applyLearn_def
    unfolding setWatch1_def
    unfolding setWatch2_def
    by (auto simp add:Let_def)
  ultimately
  show ?thesis
    by simp
qed

lemma InvariantCllCharacterizationAfterApplyLearn:
assumes
  "InvariantUniq (getM state)"
  "InvariantClCharacterization (getCl state) (getC state) (getM state)"
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)"
  "InvariantUniqC (getC state)"
  "getConflictFlag state"
shows
  "let state' = applyLearn state in 
     InvariantCllCharacterization (getCl state') (getCll state') (getC state') (getM state')"
proof (cases "getC state  [opposite (getCl state)]")
  case False
  thus ?thesis
    using assms
    unfolding applyLearn_def
    unfolding InvariantCllCharacterization_def
    by (simp add: Let_def)
next
  case True

  let ?oppC = "oppositeLiteralList (getC state)"
  let ?l = "getCl state"
  let ?ll = "getLastAssertedLiteral (removeAll ?l ?oppC) (elements (getM state))"

  have "clauseFalse (getC state) (elements (getM state))"
    using ‹getConflictFlag state
    using ‹InvariantCFalse (getConflictFlag state) (getM state) (getC state)
    unfolding InvariantCFalse_def
    by simp


  from True
  have "set (getC state)  {opposite ?l}"
    using ‹InvariantUniqC (getC state)
    using uniqOneElementCharacterization[of "getC state" "opposite ?l"]
    unfolding InvariantUniqC_def
    by (simp add: Let_def)

  have "isLastAssertedLiteral ?l ?oppC (elements (getM state))"
    using ‹InvariantClCharacterization (getCl state) (getC state) (getM state)
    unfolding InvariantClCharacterization_def
    by simp

  have "opposite ?l el (getC state)"
    using ‹isLastAssertedLiteral ?l ?oppC (elements (getM state))
    unfolding isLastAssertedLiteral_def
    using literalElListIffOppositeLiteralElOppositeLiteralList[of "?l" "?oppC"]
    by simp

  have "removeAll ?l ?oppC  []"
  proof-
    { 
      assume "¬ ?thesis"
      hence "set ?oppC  {?l}"
        using set_removeAll[of "?l" "?oppC"]
        by auto
      have "set (getC state)  {opposite ?l}"
      proof
        fix x
        assume "x  set (getC state)"
        hence "opposite x  set ?oppC"
          using literalElListIffOppositeLiteralElOppositeLiteralList[of "x" "getC state"]
          by simp
        hence "opposite x  {?l}"
          using ‹set ?oppC  {?l}
          by auto
        thus "x  {opposite ?l}"
          using oppositeSymmetry[of "x" "?l"]
          by force
      qed
      hence False
        using ‹set (getC state)  {opposite ?l}
        using ‹opposite ?l el getC state
        by (auto simp add: Let_def)
    } thus ?thesis
      by auto
  qed

  have "clauseFalse (oppositeLiteralList (removeAll ?l ?oppC)) (elements (getM state))"
    using ‹clauseFalse (getC state) (elements (getM state))
    using oppositeLiteralListRemove[of "?l" "?oppC"]
    by (simp add: clauseFalseIffAllLiteralsAreFalse)
  moreover 
  have "oppositeLiteralList (removeAll ?l ?oppC)  []"
    using ‹removeAll ?l ?oppC  []
    using oppositeLiteralListNonempty
    by simp
  ultimately
  have "isLastAssertedLiteral ?ll (removeAll ?l ?oppC) (elements (getM state))"
    using getLastAssertedLiteralCharacterization[of "oppositeLiteralList (removeAll ?l ?oppC)" "elements (getM state)"]
    using ‹InvariantUniq (getM state)
    unfolding InvariantUniq_def
    by auto
  thus ?thesis
    using ‹set (getC state)  {opposite ?l}
    unfolding applyLearn_def
    unfolding setWatch1_def
    unfolding setWatch2_def
    unfolding InvariantCllCharacterization_def
    by (auto simp add:Let_def)
qed


lemma InvariantConflictClauseCharacterizationAfterApplyLearn:
assumes
  "getConflictFlag state"
  "InvariantConflictClauseCharacterization (getConflictFlag state) (getConflictClause state) (getF state) (getM state)"
shows
  "let state' = applyLearn state in
       InvariantConflictClauseCharacterization (getConflictFlag state') (getConflictClause state') (getF state') (getM state')"
proof-
  have "getConflictClause state < length (getF state)"
    using assms
    unfolding InvariantConflictClauseCharacterization_def
    by (auto simp add: Let_def)
  hence "nth ((getF state) @ [getC state]) (getConflictClause state) = 
    nth (getF state) (getConflictClause state)"
    by (simp add: nth_append)
  thus ?thesis
    using ‹InvariantConflictClauseCharacterization (getConflictFlag state) (getConflictClause state) (getF state) (getM state)
    unfolding InvariantConflictClauseCharacterization_def
    unfolding applyLearn_def
    unfolding setWatch1_def
    unfolding setWatch2_def
    by (auto simp add: Let_def clauseFalseAppendValuation)
qed

lemma InvariantGetReasonIsReasonAfterApplyLearn:
assumes
  "InvariantGetReasonIsReason (getReason state) (getF state) (getM state) (set (getQ state))"
shows
  "let state' = applyLearn state in
    InvariantGetReasonIsReason (getReason state') (getF state') (getM state') (set (getQ state'))
  "
proof (cases "getC state = [opposite (getCl state)]")
  case True
  thus ?thesis
    unfolding applyLearn_def
    using assms
    by (simp add: Let_def)
next
  case False
  have "InvariantGetReasonIsReason (getReason state) ((getF state) @ [getC state]) (getM state) (set (getQ state))"
    using assms
    using nth_append[of "getF state" "[getC state]"]
    unfolding InvariantGetReasonIsReason_def
    by auto
  thus ?thesis
    using False
    unfolding applyLearn_def
    unfolding setWatch1_def
    unfolding setWatch2_def
    by (simp add: Let_def)
qed

lemma InvariantQCharacterizationAfterApplyLearn:
assumes
  "getConflictFlag state"
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"
shows
  "let state' = applyLearn state in
      InvariantQCharacterization (getConflictFlag state') (getQ state') (getF state') (getM state')"
using assms
unfolding InvariantQCharacterization_def
unfolding applyLearn_def
unfolding setWatch1_def
unfolding setWatch2_def
by (simp add: Let_def)

lemma InvariantUniqQAfterApplyLearn:
assumes
  "InvariantUniqQ (getQ state)"
shows
  "let state' = applyLearn state in
      InvariantUniqQ (getQ state')"
using assms
unfolding applyLearn_def
unfolding setWatch1_def
unfolding setWatch2_def
by (simp add: Let_def)

lemma InvariantConflictFlagCharacterizationAfterApplyLearn:
assumes
  "getConflictFlag state"
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)"
shows
  "let state' = applyLearn state in
      InvariantConflictFlagCharacterization (getConflictFlag state') (getF state') (getM state')"
using assms
unfolding InvariantConflictFlagCharacterization_def
unfolding applyLearn_def
unfolding setWatch1_def
unfolding setWatch2_def
by (auto simp add: Let_def formulaFalseIffContainsFalseClause)

lemma InvariantNoDecisionsWhenConflictNorUnitAfterApplyLearn:
assumes 
  "InvariantUniq (getM state)"
  "InvariantConsistent (getM state)"
  "InvariantNoDecisionsWhenConflict (getF state) (getM state) (currentLevel (getM state))"
  "InvariantNoDecisionsWhenUnit (getF state) (getM state) (currentLevel (getM state))"
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)" and
  "InvariantClCharacterization (getCl state) (getC state) (getM state)"
  "InvariantClCurrentLevel (getCl state) (getM state)"
  "InvariantUniqC (getC state)"

  "getConflictFlag state"
  "isUIP (opposite (getCl state)) (getC state) (getM state)"
  "currentLevel (getM state) > 0"
shows
  "let state' = applyLearn state in
      InvariantNoDecisionsWhenConflict (getF state) (getM state') (currentLevel (getM state'))  
      InvariantNoDecisionsWhenUnit (getF state) (getM state') (currentLevel (getM state'))  
      InvariantNoDecisionsWhenConflict [getC state] (getM state') (getBackjumpLevel state')  
      InvariantNoDecisionsWhenUnit [getC state] (getM state') (getBackjumpLevel state')"
proof-
  let ?state' = "applyLearn state"
  let ?l = "getCl state"

  have  "clauseFalse (getC state) (elements (getM state))"
    using ‹getConflictFlag state
    using ‹InvariantCFalse (getConflictFlag state) (getM state) (getC state)
    unfolding InvariantCFalse_def
    by simp

  have "getM ?state' = getM state" "getC ?state' = getC state" 
    "getCl ?state' = getCl state" "getConflictFlag ?state' = getConflictFlag state"
    unfolding applyLearn_def
    unfolding setWatch2_def
    unfolding setWatch1_def
    by (auto simp add: Let_def)

  hence "InvariantNoDecisionsWhenConflict (getF state) (getM ?state') (currentLevel (getM ?state'))  
         InvariantNoDecisionsWhenUnit (getF state) (getM ?state') (currentLevel (getM ?state'))"
    using ‹InvariantNoDecisionsWhenConflict (getF state) (getM state) (currentLevel (getM state))
    using ‹InvariantNoDecisionsWhenUnit (getF state) (getM state) (currentLevel (getM state))
    by simp
  moreover
  have "InvariantCllCharacterization (getCl ?state') (getCll ?state') (getC ?state') (getM ?state')"
    using assms
    using InvariantCllCharacterizationAfterApplyLearn[of "state"]
    by (simp add: Let_def)
  hence "isMinimalBackjumpLevel (getBackjumpLevel ?state') (opposite ?l) (getC ?state') (getM ?state')"
    using assms
    using ‹getM ?state' = getM state ‹getC ?state' = getC state 
      ‹getCl ?state' = getCl state ‹getConflictFlag ?state' = getConflictFlag state
    using isMinimalBackjumpLevelGetBackjumpLevel[of "?state'"]
    unfolding isUIP_def
    unfolding SatSolverVerification.isUIP_def
    by (simp add: Let_def)
  hence "getBackjumpLevel ?state' < elementLevel ?l (getM ?state')"
    unfolding isMinimalBackjumpLevel_def
    unfolding isBackjumpLevel_def
    by simp
  hence "getBackjumpLevel ?state' < currentLevel (getM ?state')"
    using elementLevelLeqCurrentLevel[of "?l" "getM ?state'"]
    by simp

  have "InvariantNoDecisionsWhenConflict [getC state] (getM ?state') (getBackjumpLevel ?state')  
        InvariantNoDecisionsWhenUnit [getC state] (getM ?state') (getBackjumpLevel ?state')"
  proof-
    {
      fix clause::Clause
      assume "clause el [getC state]"
      hence "clause = getC state"
        by simp
      
      have "( level'. level' < (getBackjumpLevel ?state')  
                ¬ clauseFalse clause (elements (prefixToLevel level' (getM ?state'))))  
            ( level'. level' < (getBackjumpLevel ?state')  
                ¬ ( l. isUnitClause clause l (elements (prefixToLevel level' (getM ?state')))))" (is "?false  ?unit")
      proof(cases "getC state = [opposite ?l]")
        case True
        thus ?thesis
          using ‹getM ?state' = getM state ‹getC ?state' = getC state ‹getCl ?state' = getCl state 
          unfolding getBackjumpLevel_def
          by (simp add: Let_def)
      next
        case False
        hence "getF ?state' = getF state @ [getC state]" 
          unfolding applyLearn_def
          unfolding setWatch2_def
          unfolding setWatch1_def
          by (auto simp add: Let_def)

        show ?thesis
        proof-
          have "?unit"
            using clause = getC state
            using ‹InvariantUniq (getM state)
            using ‹InvariantConsistent (getM state)
            using ‹getM ?state' = getM state ‹getC ?state' = getC state
            using ‹clauseFalse (getC state) (elements (getM state))
            using ‹isMinimalBackjumpLevel (getBackjumpLevel ?state') (opposite ?l) (getC ?state') (getM ?state')
            using isMinimalBackjumpLevelEnsuresIsNotUnitBeforePrefix[of "getM ?state'" "getC ?state'" "getBackjumpLevel ?state'" "opposite ?l"]
            unfolding InvariantUniq_def
            unfolding InvariantConsistent_def
            by simp
          moreover
          have "isUnitClause (getC state) (opposite ?l) (elements (prefixToLevel (getBackjumpLevel ?state') (getM state)))"
            using ‹InvariantUniq (getM state)
            using ‹InvariantConsistent (getM state)
            using ‹isMinimalBackjumpLevel (getBackjumpLevel ?state') (opposite ?l) (getC ?state') (getM ?state')
            using ‹getM ?state' = getM state ‹getC ?state' = getC state
            using ‹clauseFalse (getC state) (elements (getM state))
            using isBackjumpLevelEnsuresIsUnitInPrefix[of "getM ?state'" "getC ?state'" "getBackjumpLevel ?state'" "opposite ?l"]
            unfolding isMinimalBackjumpLevel_def
            unfolding InvariantUniq_def
            unfolding InvariantConsistent_def
            by simp
          hence "¬ clauseFalse (getC state) (elements (prefixToLevel (getBackjumpLevel ?state') (getM state)))"
            unfolding isUnitClause_def
            by (auto simp add: clauseFalseIffAllLiteralsAreFalse)
          have "?false"
          proof
            fix level'
            show "level' < getBackjumpLevel ?state'  ¬ clauseFalse clause (elements (prefixToLevel level' (getM ?state')))"
            proof
              assume "level' < getBackjumpLevel ?state'"
              show "¬ clauseFalse clause (elements (prefixToLevel level' (getM ?state')))"
              proof-
                have "isPrefix (prefixToLevel level' (getM state)) (prefixToLevel (getBackjumpLevel ?state') (getM state))"
                  using level' < getBackjumpLevel ?state'
                  using isPrefixPrefixToLevelLowerLevel[of "level'" "getBackjumpLevel ?state'" "getM state"]
                  by simp
                then obtain s
                  where "prefixToLevel level' (getM state) @ s = prefixToLevel (getBackjumpLevel ?state') (getM state)"
                  unfolding isPrefix_def
                  by auto
                hence "prefixToLevel (getBackjumpLevel ?state') (getM state) = prefixToLevel level' (getM state) @ s"
                  by (rule sym)
                thus ?thesis
                  using ‹getM ?state' = getM state
                  using clause = getC state
                  using ¬ clauseFalse (getC state) (elements (prefixToLevel (getBackjumpLevel ?state') (getM state)))
                  unfolding isPrefix_def
                  by (auto simp add: clauseFalseIffAllLiteralsAreFalse)
              qed
            qed
          qed
          ultimately
          show ?thesis
            by simp
        qed
      qed
    } thus ?thesis
      unfolding InvariantNoDecisionsWhenConflict_def
      unfolding InvariantNoDecisionsWhenUnit_def
      by (auto simp add: formulaFalseIffContainsFalseClause)
  qed
  ultimately
  show ?thesis
    by (simp add: Let_def)
qed

lemma InvariantEquivalentZLAfterApplyLearn:
assumes
  "InvariantEquivalentZL (getF state) (getM state) F0" and
  "InvariantCEntailed (getConflictFlag state) F0 (getC state)" and
  "getConflictFlag state"
shows
  "let state' = applyLearn state in 
         InvariantEquivalentZL (getF state') (getM state') F0"
proof-
  let ?M0 = "val2form (elements (prefixToLevel 0 (getM state)))"
  have "equivalentFormulae F0 (getF state @ ?M0)"
    using ‹InvariantEquivalentZL (getF state) (getM state) F0
    using equivalentFormulaeSymmetry[of "F0" "getF state @ ?M0"]
    unfolding InvariantEquivalentZL_def
    by simp
  moreover
  have "formulaEntailsClause (getF state @ ?M0) (getC state)"
    using assms
    unfolding InvariantEquivalentZL_def
    unfolding InvariantCEntailed_def
    unfolding equivalentFormulae_def
    unfolding formulaEntailsClause_def
    by auto
  ultimately
  have "equivalentFormulae F0 ((getF state @ ?M0) @ [getC state])"
    using extendEquivalentFormulaWithEntailedClause[of "F0" "getF state @ ?M0" "getC state"]
    by simp
  hence "equivalentFormulae ((getF state @ ?M0) @ [getC state]) F0"
    by (simp add: equivalentFormulaeSymmetry)
  have "equivalentFormulae ((getF state) @ [getC state] @ ?M0) F0"
  proof-
    {
      fix valuation::Valuation
      have "formulaTrue ((getF state @ ?M0) @ [getC state]) valuation = formulaTrue ((getF state) @ [getC state] @ ?M0) valuation"
        by (simp add: formulaTrueIffAllClausesAreTrue)
    }
    thus ?thesis
      using ‹equivalentFormulae ((getF state @ ?M0) @ [getC state]) F0
      unfolding equivalentFormulae_def
      by auto
  qed
  thus ?thesis
    using assms
    unfolding InvariantEquivalentZL_def
    unfolding applyLearn_def
    unfolding setWatch1_def
    unfolding setWatch2_def
    by (auto simp add: Let_def)
qed


lemma InvariantVarsFAfterApplyLearn:
assumes
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)"
  "getConflictFlag state"
  "InvariantVarsF (getF state) F0 Vbl"
  "InvariantVarsM (getM state) F0 Vbl"
shows
  "let state' = applyLearn state in 
     InvariantVarsF (getF state') F0 Vbl
  "
proof-
  from assms
  have "clauseFalse (getC state) (elements (getM state))"
    unfolding InvariantCFalse_def
    by simp
  hence "vars (getC state)  vars (elements (getM state))"
    using valuationContainsItsFalseClausesVariables[of "getC state" "elements (getM state)"]
    by simp
  thus ?thesis
    using applyLearnPreservedVariables[of "state"]
    using assms
    using varsAppendFormulae[of "getF state" "[getC state]"]
    unfolding InvariantVarsF_def
    unfolding InvariantVarsM_def
    by (auto simp add: Let_def)
qed


(******************************************************************************)
(*           A P P L Y    B A C K J U M P                                     *)
(******************************************************************************)

lemma applyBackjumpEffect:
assumes
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and

  "getConflictFlag state"
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)" and
  "InvariantCEntailed (getConflictFlag state) F0 (getC state)" and
  "InvariantClCharacterization (getCl state) (getC state) (getM state)" and
  "InvariantCllCharacterization (getCl state) (getCll state) (getC state) (getM state)" and
  "InvariantClCurrentLevel (getCl state) (getM state)"
  "InvariantUniqC (getC state)"
  
  "isUIP (opposite (getCl state)) (getC state) (getM state)"
  "currentLevel (getM state) > 0"
shows
  "let l = (getCl state) in
   let bClause = (getC state) in
   let bLiteral = opposite l in
   let level = getBackjumpLevel state in
   let prefix = prefixToLevel level (getM state) in
   let state'' = applyBackjump state in 
         (formulaEntailsClause F0 bClause  
          isUnitClause bClause bLiteral (elements prefix)  
          (getM state'') = prefix @ [(bLiteral, False)])  
          getF state'' = getF state"
proof-
  let ?l = "getCl state"
  let ?level = "getBackjumpLevel state"
  let ?prefix = "prefixToLevel ?level (getM state)"
  let ?state' = "state getConflictFlag := False, getQ := [], getM := ?prefix "
  let ?state'' = "applyBackjump state"

  have "clauseFalse (getC state) (elements (getM state))"
    using ‹getConflictFlag state
    using ‹InvariantCFalse (getConflictFlag state) (getM state) (getC state)
    unfolding InvariantCFalse_def
    by simp

  have "formulaEntailsClause F0 (getC state)"
    using ‹getConflictFlag state
    using ‹InvariantCEntailed (getConflictFlag state) F0 (getC state)
    unfolding InvariantCEntailed_def
    by simp

  have "isBackjumpLevel ?level (opposite ?l) (getC state) (getM state)"
    using assms
    using isMinimalBackjumpLevelGetBackjumpLevel[of "state"]
    unfolding isMinimalBackjumpLevel_def
    by (simp add: Let_def)
  then have "isUnitClause (getC state) (opposite ?l) (elements ?prefix)"
    using assms
    using ‹clauseFalse (getC state) (elements (getM state))
    using isBackjumpLevelEnsuresIsUnitInPrefix[of "getM state" "getC state" "?level" "opposite ?l"]
    unfolding InvariantConsistent_def
    unfolding InvariantUniq_def
    by simp
  moreover
  have "getM ?state'' = ?prefix @ [(opposite ?l, False)]" "getF ?state'' = getF state"
    unfolding applyBackjump_def
    using assms
    using assertLiteralEffect
    unfolding setReason_def
    by (auto simp add: Let_def)
  ultimately
  show ?thesis
    using ‹formulaEntailsClause F0 (getC state)
    by (simp add: Let_def)
qed

lemma applyBackjumpPreservedVariables:
assumes 
"InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)"
"InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)"
shows 
"let state' = applyBackjump state in 
   getSATFlag state' = getSATFlag state"
using assms
unfolding applyBackjump_def
unfolding setReason_def
by (auto simp add: Let_def assertLiteralEffect)


lemma InvariantWatchCharacterizationInBackjumpPrefix:
assumes
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"

shows
  "let l = getCl state in
   let level = getBackjumpLevel state in
   let prefix = prefixToLevel level (getM state) in
   let state' = state getConflictFlag := False, getQ := [], getM := prefix  in
     InvariantWatchCharacterization (getF state') (getWatch1 state') (getWatch2 state') (getM state')"
proof-
  let ?l = "getCl state"
  let ?level = "getBackjumpLevel state"
  let ?prefix = "prefixToLevel ?level (getM state)"
  let ?state' = "state getConflictFlag := False, getQ := [], getM := ?prefix "

    {
      fix c w1 w2
      assume "c < length (getF state)" "Some w1 = getWatch1 state c" "Some w2 = getWatch2 state c"
      with ‹InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)
      have "watchCharacterizationCondition w1 w2 (getM state) (nth (getF state) c)"
        "watchCharacterizationCondition w2 w1 (getM state) (nth (getF state) c)"
        unfolding InvariantWatchCharacterization_def
        by auto

      let ?clause = "nth (getF state) c"
      let "?a state w1 w2" = " l. l el ?clause  literalTrue l (elements (getM state))  
                                   elementLevel l (getM state)  elementLevel (opposite w1) (getM state)"
      let "?b state w1 w2" = " l. l el ?clause  l  w1  l  w2  
                             literalFalse l (elements (getM state))  
                             elementLevel (opposite l) (getM state)  elementLevel (opposite w1) (getM state)"

      have "watchCharacterizationCondition w1 w2 (getM ?state') ?clause  
            watchCharacterizationCondition w2 w1 (getM ?state') ?clause"
      proof-
        {
          assume "literalFalse w1 (elements (getM ?state'))"
          hence "literalFalse w1 (elements (getM state))"
            using isPrefixPrefixToLevel[of "?level" "getM state"]
            using isPrefixElements[of "prefixToLevel ?level (getM state)" "getM state"]
            using prefixIsSubset[of "elements (prefixToLevel ?level (getM state))" "elements (getM state)"]
            by auto

          from ‹literalFalse w1 (elements (getM ?state'))
          have "elementLevel (opposite w1) (getM state)  ?level"
            using prefixToLevelElementsElementLevel[of  "opposite w1" "?level" "getM state"]
            by simp

          from ‹literalFalse w1 (elements (getM ?state'))
          have "elementLevel (opposite w1) (getM ?state') = elementLevel (opposite w1) (getM state)"
            using elementLevelPrefixElement
            by simp


          have "?a ?state' w1 w2  ?b ?state' w1 w2"
          proof (cases "?a state w1 w2")
            case True
            then obtain l
              where "l el ?clause" "literalTrue l (elements (getM state))" 
              "elementLevel l (getM state)  elementLevel (opposite w1) (getM state)"
            by auto
            
            have "literalTrue l (elements (getM ?state'))"
              using ‹elementLevel (opposite w1) (getM state)  ?level
              using elementLevelLtLevelImpliesMemberPrefixToLevel[of "l" "getM state" "?level"]
              using ‹elementLevel l (getM state)  elementLevel (opposite w1) (getM state)
              using ‹literalTrue l (elements (getM state))
              by simp
            moreover
            from ‹literalTrue l (elements (getM ?state'))
            have "elementLevel l (getM ?state') = elementLevel l (getM state)"
              using elementLevelPrefixElement
              by simp
            ultimately 
            show ?thesis
              using ‹elementLevel (opposite w1) (getM ?state') = elementLevel (opposite w1) (getM state)
              using ‹elementLevel l (getM state)  elementLevel (opposite w1) (getM state)
              using l el ?clause
              by auto
          next
            case False
            {
              fix l
              assume "l el ?clause" "l  w1" "l  w2"
              hence "literalFalse l (elements (getM state))" 
                "elementLevel (opposite l) (getM state)  elementLevel (opposite w1) (getM state)"
                using ‹literalFalse w1 (elements (getM state))
                using False
                using ‹watchCharacterizationCondition w1 w2 (getM state) ?clause
                unfolding watchCharacterizationCondition_def
                by auto
              
              have "literalFalse l (elements (getM ?state'))  
                elementLevel (opposite l) (getM ?state')  elementLevel (opposite w1) (getM ?state')"
              proof-
                have "literalFalse l (elements (getM ?state'))"
                  using ‹elementLevel (opposite w1) (getM state)  ?level
                  using elementLevelLtLevelImpliesMemberPrefixToLevel[of "opposite l" "getM state" "?level"]
                  using ‹elementLevel (opposite l) (getM state)  elementLevel (opposite w1) (getM state)
                  using ‹literalFalse l (elements (getM state))
                  by simp
                moreover
                from ‹literalFalse l (elements (getM ?state'))
                have "elementLevel (opposite l) (getM ?state') = elementLevel (opposite l) (getM state)"
                  using elementLevelPrefixElement
                  by simp
                ultimately 
                show ?thesis
                  using ‹elementLevel (opposite w1) (getM ?state') = elementLevel (opposite w1) (getM state)
                  using ‹elementLevel (opposite l) (getM state)  elementLevel (opposite w1) (getM state)
                  using l el ?clause
                  by auto
              qed
            }
            thus ?thesis
              by auto
          qed
        }
        moreover
        {
          assume "literalFalse w2 (elements (getM ?state'))"
          hence "literalFalse w2 (elements (getM state))"
            using isPrefixPrefixToLevel[of "?level" "getM state"]
            using isPrefixElements[of "prefixToLevel ?level (getM state)" "getM state"]
            using prefixIsSubset[of "elements (prefixToLevel ?level (getM state))" "elements (getM state)"]
            by auto

          from ‹literalFalse w2 (elements (getM ?state'))
          have "elementLevel (opposite w2) (getM state)  ?level"
            using prefixToLevelElementsElementLevel[of "opposite w2" "?level" "getM state"]
            by simp

          from ‹literalFalse w2 (elements (getM ?state'))
          have "elementLevel (opposite w2) (getM ?state') = elementLevel (opposite w2) (getM state)"
            using elementLevelPrefixElement
            by simp

          have "?a ?state' w2 w1  ?b ?state' w2 w1"
          proof (cases "?a state w2 w1")
            case True
            then obtain l
              where "l el ?clause" "literalTrue l (elements (getM state))" 
              "elementLevel l (getM state)  elementLevel (opposite w2) (getM state)"
            by auto
            
            have "literalTrue l (elements (getM ?state'))"
              using ‹elementLevel (opposite w2) (getM state)  ?level
              using elementLevelLtLevelImpliesMemberPrefixToLevel[of "l" "getM state" "?level"]
              using ‹elementLevel l (getM state)  elementLevel (opposite w2) (getM state)
              using ‹literalTrue l (elements (getM state))
              by simp
            moreover
            from ‹literalTrue l (elements (getM ?state'))
            have "elementLevel l (getM ?state') = elementLevel l (getM state)"
              using elementLevelPrefixElement
              by simp
            ultimately 
            show ?thesis
              using ‹elementLevel (opposite w2) (getM ?state') = elementLevel (opposite w2) (getM state)
              using ‹elementLevel l (getM state)  elementLevel (opposite w2) (getM state)
              using l el ?clause
              by auto
          next
            case False
            {
              fix l
              assume "l el ?clause" "l  w1" "l  w2"
              hence "literalFalse l (elements (getM state))" 
                "elementLevel (opposite l) (getM state)  elementLevel (opposite w2) (getM state)"
                using ‹literalFalse w2 (elements (getM state))
                using False
                using ‹watchCharacterizationCondition w2 w1 (getM state) ?clause
                unfolding watchCharacterizationCondition_def
                by auto
              
              have "literalFalse l (elements (getM ?state'))  
                elementLevel (opposite l) (getM ?state')  elementLevel (opposite w2) (getM ?state')"
              proof-
                have "literalFalse l (elements (getM ?state'))"
                  using ‹elementLevel (opposite w2) (getM state)  ?level
                  using elementLevelLtLevelImpliesMemberPrefixToLevel[of "opposite l" "getM state" "?level"]
                  using ‹elementLevel (opposite l) (getM state)  elementLevel (opposite w2) (getM state)
                  using ‹literalFalse l (elements (getM state))
                  by simp
                moreover
                from ‹literalFalse l (elements (getM ?state'))
                have "elementLevel (opposite l) (getM ?state') = elementLevel (opposite l) (getM state)"
                  using elementLevelPrefixElement
                  by simp
                ultimately 
                show ?thesis
                  using ‹elementLevel (opposite w2) (getM ?state') = elementLevel (opposite w2) (getM state)
                  using ‹elementLevel (opposite l) (getM state)  elementLevel (opposite w2) (getM state)
                  using l el ?clause
                  by auto
              qed
            }
            thus ?thesis
              by auto
          qed
        }
        ultimately
        show ?thesis
          unfolding watchCharacterizationCondition_def
          by auto
      qed
    }
    thus ?thesis
      unfolding InvariantWatchCharacterization_def
      by auto
qed

lemma InvariantConsistentAfterApplyBackjump:
assumes
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and

  "getConflictFlag state"
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)" and
  "InvariantUniqC (getC state)"
  "InvariantCEntailed (getConflictFlag state) F0 (getC state)" and
  "InvariantClCharacterization (getCl state) (getC state) (getM state)" and
  "InvariantCllCharacterization (getCl state) (getCll state) (getC state) (getM state)" and
  "InvariantClCurrentLevel (getCl state) (getM state)"

  "currentLevel (getM state) > 0"
  "isUIP (opposite (getCl state)) (getC state) (getM state)"
shows
  "let state' = applyBackjump state in 
         InvariantConsistent (getM state')"
proof-
  let ?l = "getCl state"
  let ?bClause = "getC state"
  let ?bLiteral = "opposite ?l"
  let ?level = "getBackjumpLevel state" 
  let ?prefix = "prefixToLevel ?level (getM state)"
  let ?state'' = "applyBackjump state"

  have "formulaEntailsClause F0 ?bClause" and
    "isUnitClause ?bClause ?bLiteral (elements ?prefix)" and
    "getM ?state'' = ?prefix @ [(?bLiteral, False)]"
    using assms
    using applyBackjumpEffect[of "state"]
    by (auto simp add: Let_def)
  thus ?thesis
    using ‹InvariantConsistent (getM state)
    using InvariantConsistentAfterBackjump[of "getM state" "?prefix" "?bClause" "?bLiteral" "getM ?state''"]
    using isPrefixPrefixToLevel
    by (auto simp add: Let_def)
qed
      

lemma InvariantUniqAfterApplyBackjump:
assumes
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and

  "getConflictFlag state"
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)" and
  "InvariantUniqC (getC state)"
  "InvariantCEntailed (getConflictFlag state) F0 (getC state)" and
  "InvariantClCharacterization (getCl state) (getC state) (getM state)" and
  "InvariantCllCharacterization (getCl state) (getCll state) (getC state) (getM state)" and
  "InvariantClCurrentLevel (getCl state) (getM state)"

  "currentLevel (getM state) > 0"
  "isUIP (opposite (getCl state)) (getC state) (getM state)"
shows
  "let state' = applyBackjump state in
      InvariantUniq (getM state')"
proof-
  let ?l = "getCl state"
  let ?bClause = "getC state"
  let ?bLiteral = "opposite ?l"
  let ?level = "getBackjumpLevel state" 
  let ?prefix = "prefixToLevel ?level (getM state)"
  let ?state'' = "applyBackjump state"

  have "clauseFalse (getC state) (elements (getM state))"
    using ‹getConflictFlag state
    using ‹InvariantCFalse (getConflictFlag state) (getM state) (getC state)
    unfolding InvariantCFalse_def
    by simp
    
  have "isUnitClause ?bClause ?bLiteral (elements ?prefix)" and
    "getM ?state'' = ?prefix @ [(?bLiteral, False)]"
    using assms
    using applyBackjumpEffect[of "state"]
    by (auto simp add: Let_def)
  thus ?thesis
    using ‹InvariantUniq (getM state)
    using InvariantUniqAfterBackjump[of "getM state" "?prefix" "?bClause" "?bLiteral" "getM ?state''"]
    using isPrefixPrefixToLevel
    by (auto simp add: Let_def)
qed

lemma WatchInvariantsAfterApplyBackjump:
assumes
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)" and 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"

  "getConflictFlag state"
  "InvariantUniqC (getC state)"
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)" and
  "InvariantCEntailed (getConflictFlag state) F0 (getC state)" and
  "InvariantClCharacterization (getCl state) (getC state) (getM state)" and
  "InvariantCllCharacterization (getCl state) (getCll state) (getC state) (getM state)" and
  "InvariantClCurrentLevel (getCl state) (getM state)"

  "isUIP (opposite (getCl state)) (getC state) (getM state)"
  "currentLevel (getM state) > 0"
shows
  "let state' = (applyBackjump state) in
     InvariantWatchesEl (getF state') (getWatch1 state') (getWatch2 state')  
     InvariantWatchesDiffer (getF state') (getWatch1 state') (getWatch2 state')  
     InvariantWatchCharacterization (getF state') (getWatch1 state') (getWatch2 state') (getM state')  
     InvariantWatchListsContainOnlyClausesFromF (getWatchList state') (getF state')  
     InvariantWatchListsUniq (getWatchList state')  
     InvariantWatchListsCharacterization (getWatchList state') (getWatch1 state') (getWatch2 state')"
(is "let state' = (applyBackjump state) in ?inv state'")
proof-
  let ?l = "getCl state"
  let ?level = "getBackjumpLevel state"
  let ?prefix = "prefixToLevel ?level (getM state)"
  let ?state' = "state getConflictFlag := False, getQ := [], getM := ?prefix "
  let ?state'' = "setReason (opposite (getCl state)) (length (getF state) - 1) ?state'"
  let ?state0 = "assertLiteral (opposite (getCl state)) False ?state''"

  have "getF ?state' = getF state" "getWatchList ?state' = getWatchList state" 
    "getWatch1 ?state' = getWatch1 state" "getWatch2 ?state' = getWatch2 state"
    unfolding setReason_def
    by (auto simp add: Let_def)
  moreover
  have "InvariantWatchCharacterization (getF ?state') (getWatch1 ?state') (getWatch2 ?state') (getM ?state')"
    using assms
    using InvariantWatchCharacterizationInBackjumpPrefix[of "state"]
    unfolding setReason_def
    by (simp add: Let_def)
  moreover 
  have "InvariantConsistent (?prefix @ [(opposite ?l, False)])"
    using assms
    using InvariantConsistentAfterApplyBackjump[of "state" "F0"]
    using assertLiteralEffect
    unfolding applyBackjump_def
    unfolding setReason_def
    by (auto simp add: Let_def split: if_split_asm)
  moreover
  have "InvariantUniq (?prefix @ [(opposite ?l, False)])"
    using assms
    using InvariantUniqAfterApplyBackjump[of "state" "F0"]
    using assertLiteralEffect
    unfolding applyBackjump_def
    unfolding setReason_def
    by (auto simp add: Let_def split: if_split_asm)
  ultimately
  show ?thesis
    using assms
    using WatchInvariantsAfterAssertLiteral[of "?state''" "opposite ?l" "False"]
    using WatchInvariantsAfterAssertLiteral[of "?state'" "opposite ?l" "False"]
    using InvariantWatchCharacterizationAfterAssertLiteral[of "?state''" "opposite ?l" "False"]
    using InvariantWatchCharacterizationAfterAssertLiteral[of "?state'" "opposite ?l" "False"]
    unfolding applyBackjump_def
    unfolding setReason_def
    by (auto simp add: Let_def)
qed

lemma InvariantUniqQAfterApplyBackjump:
assumes 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)"
shows
  "let state' = applyBackjump state in
      InvariantUniqQ (getQ state')"
proof-
  let ?l = "getCl state"
  let ?level = "getBackjumpLevel state"
  let ?prefix = "prefixToLevel ?level (getM state)"
  let ?state' = "state getConflictFlag := False, getQ := [], getM := ?prefix "
  let ?state'' = "setReason (opposite (getCl state)) (length (getF state) - 1) ?state'"

  show ?thesis
    using assms
    unfolding applyBackjump_def
    using InvariantUniqQAfterAssertLiteral[of "?state'" "opposite ?l" "False"]
    using InvariantUniqQAfterAssertLiteral[of "?state''" "opposite ?l" "False"]
    unfolding InvariantUniqQ_def
    unfolding setReason_def
    by (auto simp add: Let_def)
qed

  
lemma invariantQCharacterizationAfterApplyBackjump_1:
assumes
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)" and
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)" and
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)" and
  
  "InvariantUniqC (getC state)"
  "getC state = [opposite (getCl state)]"
  "InvariantNoDecisionsWhenUnit (getF state) (getM state) (currentLevel (getM state))"
  "InvariantNoDecisionsWhenConflict (getF state) (getM state) (currentLevel (getM state))"

  "getConflictFlag state"
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)" 
  "InvariantCEntailed (getConflictFlag state) F0 (getC state)" and
  "InvariantClCharacterization (getCl state) (getC state) (getM state)" and
  "InvariantCllCharacterization (getCl state) (getCll state) (getC state) (getM state)" and
  "InvariantClCurrentLevel (getCl state) (getM state)"

  "currentLevel (getM state) > 0"
  "isUIP (opposite (getCl state)) (getC state) (getM state)"
shows
  "let state'' = (applyBackjump state) in
     InvariantQCharacterization (getConflictFlag state'') (getQ state'') (getF state'') (getM state'')"
proof-
  let ?l = "getCl state"
  let ?level = "getBackjumpLevel state"
  let ?prefix = "prefixToLevel ?level (getM state)"
  let ?state' = "state getConflictFlag := False, getQ := [], getM := ?prefix "
  let ?state'' = "setReason (opposite (getCl state)) (length (getF state) - 1) ?state'"

  let ?state'1 = "assertLiteral  (opposite ?l) False ?state'"
  let ?state''1 = "assertLiteral  (opposite ?l) False ?state''"

  have "?level < elementLevel ?l (getM state)"
    using assms
    using isMinimalBackjumpLevelGetBackjumpLevel[of "state"]
    unfolding isMinimalBackjumpLevel_def
    unfolding isBackjumpLevel_def
    by (simp add: Let_def)
  hence "?level < currentLevel (getM state)"
    using elementLevelLeqCurrentLevel[of "?l" "getM state"]
    by simp
  hence "InvariantQCharacterization (getConflictFlag ?state') (getQ ?state') (getF ?state') (getM ?state')"
        "InvariantConflictFlagCharacterization (getConflictFlag ?state') (getF ?state') (getM ?state')"
    unfolding InvariantQCharacterization_def
    unfolding InvariantConflictFlagCharacterization_def
    using ‹InvariantNoDecisionsWhenConflict (getF state) (getM state) (currentLevel (getM state))
    using ‹InvariantNoDecisionsWhenUnit (getF state) (getM state) (currentLevel (getM state))
    unfolding InvariantNoDecisionsWhenConflict_def
    unfolding InvariantNoDecisionsWhenUnit_def
    unfolding applyBackjump_def
    by (auto simp add: Let_def set_conv_nth)
  moreover
  have "InvariantConsistent (?prefix @  [(opposite ?l, False)])"
    using assms
    using InvariantConsistentAfterApplyBackjump[of "state" "F0"]
    using assertLiteralEffect
    unfolding applyBackjump_def
    unfolding setReason_def
    by (auto simp add: Let_def split: if_split_asm)
  moreover
  have "InvariantWatchCharacterization (getF ?state') (getWatch1 ?state') (getWatch2 ?state') (getM ?state')"
    using InvariantWatchCharacterizationInBackjumpPrefix[of "state"]
    using assms
    by (simp add: Let_def)
  moreover
  have "¬ opposite ?l el (getQ ?state'1)" "¬ opposite ?l el (getQ ?state''1)"
    using assertedLiteralIsNotUnit[of "?state'" "opposite ?l" "False"]
    using assertedLiteralIsNotUnit[of "?state''" "opposite ?l" "False"]
    using ‹InvariantQCharacterization (getConflictFlag ?state') (getQ ?state') (getF ?state') (getM ?state')
    using ‹InvariantConsistent (?prefix @  [(opposite ?l, False)])
    using ‹InvariantWatchCharacterization (getF ?state') (getWatch1 ?state') (getWatch2 ?state') (getM ?state')
    unfolding applyBackjump_def
    unfolding setReason_def
    using assms
    by (auto simp add: Let_def split: if_split_asm)
  hence "removeAll (opposite ?l) (getQ ?state'1) = getQ ?state'1" 
        "removeAll (opposite ?l) (getQ ?state''1) = getQ ?state''1"
    using removeAll_id[of "opposite ?l" "getQ ?state'1"]
    using removeAll_id[of "opposite ?l" "getQ ?state''1"]
    unfolding setReason_def
    by auto
  ultimately
  show ?thesis
    using assms
    using InvariantWatchCharacterizationInBackjumpPrefix[of "state"]
    using InvariantQCharacterizationAfterAssertLiteral[of "?state'" "opposite ?l" "False"]
    using InvariantQCharacterizationAfterAssertLiteral[of "?state''" "opposite ?l" "False"]
    unfolding applyBackjump_def
    unfolding setReason_def
    by (auto simp add: Let_def) 
qed


lemma invariantQCharacterizationAfterApplyBackjump_2:
fixes state::State
assumes
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)" and
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)" and
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)" and
  
  "InvariantUniqC (getC state)"
  "getC state  [opposite (getCl state)]"
  "InvariantNoDecisionsWhenUnit (butlast (getF state)) (getM state) (currentLevel (getM state))"
  "InvariantNoDecisionsWhenConflict (butlast (getF state)) (getM state) (currentLevel (getM state))"
  "getF state  []"
  "last (getF state) = getC state"

  "getConflictFlag state"
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)" and
  "InvariantCEntailed (getConflictFlag state) F0 (getC state)" and
  "InvariantClCharacterization (getCl state) (getC state) (getM state)" and
  "InvariantCllCharacterization (getCl state) (getCll state) (getC state) (getM state)" and
  "InvariantClCurrentLevel (getCl state) (getM state)"

  "currentLevel (getM state) > 0"
  "isUIP (opposite (getCl state)) (getC state) (getM state)"
shows
  "let state'' = (applyBackjump state) in
     InvariantQCharacterization (getConflictFlag state'') (getQ state'') (getF state'') (getM state'')"
proof-
  let ?l = "getCl state"
  let ?level = "getBackjumpLevel state"
  let ?prefix = "prefixToLevel ?level (getM state)"

  let ?state' = "state getConflictFlag := False, getQ := [], getM := ?prefix "
  let ?state'' = "setReason (opposite (getCl state)) (length (getF state) - 1) ?state'"

  have "?level < elementLevel ?l (getM state)"
    using assms
    using isMinimalBackjumpLevelGetBackjumpLevel[of "state"]
    unfolding isMinimalBackjumpLevel_def
    unfolding isBackjumpLevel_def
    by (simp add: Let_def)
  hence "?level < currentLevel (getM state)"
    using elementLevelLeqCurrentLevel[of "?l" "getM state"]
    by simp

  have "isUnitClause (last (getF state)) (opposite ?l) (elements ?prefix)"
    using ‹last (getF state) = getC state
    using isMinimalBackjumpLevelGetBackjumpLevel[of "state"]
    using ‹InvariantUniq (getM state)
    using ‹InvariantConsistent (getM state)
    using ‹getConflictFlag state
    using ‹InvariantUniqC (getC state)
    using ‹InvariantCFalse (getConflictFlag state) (getM state) (getC state)
    using isBackjumpLevelEnsuresIsUnitInPrefix[of "getM state" "getC state" "getBackjumpLevel state" "opposite ?l"]
    using ‹InvariantClCharacterization (getCl state) (getC state) (getM state)
    using ‹InvariantCllCharacterization (getCl state) (getCll state) (getC state) (getM state)
    using ‹InvariantClCurrentLevel (getCl state) (getM state)
    using ‹currentLevel (getM state) > 0
    using ‹isUIP (opposite (getCl state)) (getC state) (getM state)
    unfolding isMinimalBackjumpLevel_def
    unfolding InvariantUniq_def
    unfolding InvariantConsistent_def
    unfolding InvariantCFalse_def
    by (simp add: Let_def)
  hence "¬ clauseFalse (last (getF state)) (elements ?prefix)"
    unfolding isUnitClause_def
    by (auto simp add: clauseFalseIffAllLiteralsAreFalse)

  have "InvariantConsistent (?prefix @  [(opposite ?l, False)])"
    using assms
    using InvariantConsistentAfterApplyBackjump[of "state" "F0"]
    using assertLiteralEffect
    unfolding applyBackjump_def
    unfolding setReason_def
    by (auto simp add: Let_def split: if_split_asm)

  have "InvariantUniq (?prefix @  [(opposite ?l, False)])"
    using assms
    using InvariantUniqAfterApplyBackjump[of "state" "F0"]
    using assertLiteralEffect
    unfolding applyBackjump_def
    unfolding setReason_def
    by (auto simp add: Let_def split: if_split_asm)

  let ?state'1 = "?state'  getQ := getQ ?state' @ [opposite ?l]"
  let ?state'2 = "assertLiteral (opposite ?l) False ?state'1"

  let ?state''1 = "?state''  getQ := getQ ?state'' @ [opposite ?l]"
  let ?state''2 = "assertLiteral (opposite ?l) False ?state''1"

  have "InvariantQCharacterization (getConflictFlag ?state') ((getQ ?state') @ [opposite ?l]) (getF ?state') (getM ?state')"
  proof-
    have " l c. c el (butlast (getF state))  ¬ isUnitClause c l (elements (getM ?state'))"
      using ‹InvariantNoDecisionsWhenUnit (butlast (getF state)) (getM state) (currentLevel (getM state))
      using ?level < currentLevel (getM state)
      unfolding InvariantNoDecisionsWhenUnit_def
      by simp

    have " l. (( c. c el (getF state)  isUnitClause c l (elements (getM ?state'))) = (l = opposite ?l))"
    proof
      fix l
      show "( c. c el (getF state)  isUnitClause c l (elements (getM ?state'))) = (l = opposite ?l)" (is "?lhs = ?rhs")
      proof
        assume "?lhs"
        then obtain c::Clause 
          where "c el (getF state)" and "isUnitClause c l (elements ?prefix)"
          by auto
        show "?rhs"
        proof (cases "c el (butlast (getF state))")
          case True
          thus ?thesis
            using  l c. c el (butlast (getF state))  ¬ isUnitClause c l (elements (getM ?state'))
            using ‹isUnitClause c l (elements ?prefix)
            by auto
        next
          case False

          from ‹getF state  []
          have "butlast (getF state) @ [last (getF state)] = getF state"
            using append_butlast_last_id[of "getF state"]
            by simp
          hence "getF state = butlast (getF state) @ [last (getF state)]"
            by (rule sym)
          with c el getF state
          have "c el butlast (getF state)  c el [last (getF state)]"
            using set_append[of "butlast (getF state)" "[last (getF state)]"]
            by auto
          hence "c = last (getF state)"
            using ¬ c el (butlast (getF state))
            by simp
          thus ?thesis
            using ‹isUnitClause (last (getF state)) (opposite ?l) (elements ?prefix)
            using ‹isUnitClause c l (elements ?prefix)
            unfolding isUnitClause_def
            by auto
        qed
        next
          from ‹getF state  []
          have "last (getF state) el (getF state)"
            by auto
          assume "?rhs"
          thus "?lhs"
            using ‹isUnitClause (last (getF state)) (opposite ?l) (elements ?prefix)
            using ‹last (getF state) el (getF state)
            by auto
      qed
    qed
    thus ?thesis
      unfolding InvariantQCharacterization_def
      by simp
  qed
  hence "InvariantQCharacterization (getConflictFlag ?state'1) (getQ ?state'1) (getF ?state'1) (getM ?state'1)"
    by simp
  hence "InvariantQCharacterization (getConflictFlag ?state''1) (getQ ?state''1) (getF ?state''1) (getM ?state''1)"
    unfolding setReason_def
    by simp

  have "InvariantWatchCharacterization (getF ?state'1) (getWatch1 ?state'1) (getWatch2 ?state'1) (getM ?state'1)"
    using InvariantWatchCharacterizationInBackjumpPrefix[of "state"]
    using assms
    by (simp add: Let_def)
  hence "InvariantWatchCharacterization (getF ?state''1) (getWatch1 ?state''1) (getWatch2 ?state''1) (getM ?state''1)"
    unfolding setReason_def
    by simp

  have "InvariantWatchCharacterization (getF ?state') (getWatch1 ?state') (getWatch2 ?state') (getM ?state')"
    using InvariantWatchCharacterizationInBackjumpPrefix[of "state"]
    using assms
    by (simp add: Let_def)
  hence "InvariantWatchCharacterization (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') (getM ?state'')"
    unfolding setReason_def
    by simp

  have "InvariantConflictFlagCharacterization (getConflictFlag ?state'1) (getF ?state'1) (getM ?state'1)"
  proof-
    {
      fix c::Clause
      assume "c el (getF state)"
      have "¬ clauseFalse c (elements ?prefix)"
      proof (cases "c el (butlast (getF state))")
        case True
        thus ?thesis
          using ‹InvariantNoDecisionsWhenConflict (butlast (getF state)) (getM state) (currentLevel (getM state))
          using ?level < currentLevel (getM state)
          unfolding InvariantNoDecisionsWhenConflict_def
          by (simp add: formulaFalseIffContainsFalseClause)
      next
        case False
        from ‹getF state  []
        have "butlast (getF state) @ [last (getF state)] = getF state"
          using append_butlast_last_id[of "getF state"]
          by simp
        hence "getF state = butlast (getF state) @ [last (getF state)]"
          by (rule sym)
        with c el getF state
        have "c el butlast (getF state)  c el [last (getF state)]"
          using set_append[of "butlast (getF state)" "[last (getF state)]"]
          by auto
        hence "c = last (getF state)"
          using ¬ c el (butlast (getF state))
          by simp
        thus ?thesis
          using ¬ clauseFalse (last (getF state)) (elements ?prefix)
          by simp
      qed
    } thus ?thesis
      unfolding InvariantConflictFlagCharacterization_def
      by (simp add: formulaFalseIffContainsFalseClause)
  qed
  hence "InvariantConflictFlagCharacterization (getConflictFlag ?state''1) (getF ?state''1) (getM ?state''1)"
    unfolding setReason_def
    by simp
  
  
  have "InvariantQCharacterization (getConflictFlag ?state'2) (removeAll (opposite ?l) (getQ ?state'2)) (getF ?state'2) (getM ?state'2)"
    using assms
    using ‹InvariantConsistent (?prefix @  [(opposite ?l, False)])
    using ‹InvariantUniq (?prefix @  [(opposite ?l, False)])
    using ‹InvariantConflictFlagCharacterization (getConflictFlag ?state'1) (getF ?state'1) (getM ?state'1)
    using ‹InvariantWatchCharacterization (getF ?state'1) (getWatch1 ?state'1) (getWatch2 ?state'1) (getM ?state'1)
    using ‹InvariantQCharacterization (getConflictFlag ?state'1) (getQ ?state'1) (getF ?state'1) (getM ?state'1)
    using InvariantQCharacterizationAfterAssertLiteral[of "?state'1" "opposite ?l" "False"]
    by (simp add: Let_def)

  have "InvariantQCharacterization (getConflictFlag ?state''2) (removeAll (opposite ?l) (getQ ?state''2)) (getF ?state''2) (getM ?state''2)"
    using assms
    using ‹InvariantConsistent (?prefix @  [(opposite ?l, False)])
    using ‹InvariantUniq (?prefix @  [(opposite ?l, False)])
    using ‹InvariantConflictFlagCharacterization (getConflictFlag ?state''1) (getF ?state''1) (getM ?state''1)
    using ‹InvariantWatchCharacterization (getF ?state''1) (getWatch1 ?state''1) (getWatch2 ?state''1) (getM ?state''1)
    using ‹InvariantQCharacterization (getConflictFlag ?state''1) (getQ ?state''1) (getF ?state''1) (getM ?state''1)
    using InvariantQCharacterizationAfterAssertLiteral[of "?state''1" "opposite ?l" "False"]
    unfolding setReason_def
    by (simp add: Let_def)

  let ?stateB = "applyBackjump state"
  show ?thesis
  proof (cases "getBackjumpLevel state > 0")
    case False
    let ?state01 = "stategetConflictFlag := False, getM := ?prefix"
    have  "InvariantWatchesEl (getF ?state01) (getWatch1 ?state01) (getWatch2 ?state01)"
      using ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)
      unfolding InvariantWatchesEl_def
      by auto
    
    have "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state01) (getF ?state01)"
      using ‹InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)
      unfolding InvariantWatchListsContainOnlyClausesFromF_def
      by auto

    have "assertLiteral (opposite ?l) False (state getConflictFlag := False, getQ := [], getM := ?prefix ) = 
          assertLiteral (opposite ?l) False (state getConflictFlag := False, getM := ?prefix, getQ := [] )"
      using arg_cong[of "state getConflictFlag := False, getQ := [], getM := ?prefix "
                        "state getConflictFlag := False, getM := ?prefix, getQ := [] "
                        "λ x. assertLiteral (opposite ?l) False x"]
      by simp
    hence "getConflictFlag ?stateB = getConflictFlag ?state'2" 
      "getF ?stateB = getF ?state'2"  
      "getM ?stateB = getM ?state'2"
      unfolding applyBackjump_def
      using AssertLiteralStartQIreleveant[of "?state01" "opposite ?l" "False" "[]" "[opposite ?l]"]
      using ‹InvariantWatchesEl (getF ?state01) (getWatch1 ?state01) (getWatch2 ?state01)
      using ‹InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state01) (getF ?state01)
      using ¬ getBackjumpLevel state > 0
      by (auto simp add: Let_def)

    have  "set (getQ ?stateB) = set (removeAll (opposite ?l) (getQ ?state'2))"
    proof-
      have "set (getQ ?stateB) = set(getQ ?state'2) - {opposite ?l}"
      proof-
        let ?ulSet = "{ ul. ( uc. uc el (getF ?state'1)  
                                   ?l el uc  
                                   isUnitClause uc ul ((elements (getM ?state'1)) @ [opposite ?l])) }"
        have "set (getQ ?state'2) = {opposite ?l}  ?ulSet"
          using assertLiteralQEffect[of "?state'1" "opposite ?l" "False"]
          using assms
          using ‹InvariantConsistent (?prefix @  [(opposite ?l, False)])
          using ‹InvariantUniq (?prefix @  [(opposite ?l, False)])
          using ‹InvariantWatchCharacterization (getF ?state'1) (getWatch1 ?state'1) (getWatch2 ?state'1) (getM ?state'1)
          by (simp add:Let_def)
        moreover
        have "set (getQ ?stateB) = ?ulSet"
          using assertLiteralQEffect[of "?state'" "opposite ?l" "False"]
          using assms
          using ‹InvariantConsistent (?prefix @  [(opposite ?l, False)])
          using ‹InvariantUniq (?prefix @  [(opposite ?l, False)])
          using ‹InvariantWatchCharacterization (getF ?state') (getWatch1 ?state') (getWatch2 ?state') (getM ?state')
          using ¬ getBackjumpLevel state > 0
          unfolding applyBackjump_def
          by (simp add:Let_def)
        moreover
        have "¬ (opposite ?l)  ?ulSet"
          using assertedLiteralIsNotUnit[of "?state'" "opposite ?l" "False"]
          using assms
          using ‹InvariantConsistent (?prefix @  [(opposite ?l, False)])
          using ‹InvariantUniq (?prefix @  [(opposite ?l, False)])
          using ‹InvariantWatchCharacterization (getF ?state') (getWatch1 ?state') (getWatch2 ?state') (getM ?state')
          using ‹set (getQ ?stateB) = ?ulSet
          using ¬ getBackjumpLevel state > 0
          unfolding applyBackjump_def
          by (simp add: Let_def)
        ultimately
        show ?thesis
          by simp
      qed
      thus ?thesis
        by simp
    qed

    show ?thesis
      using ‹InvariantQCharacterization (getConflictFlag ?state'2) (removeAll (opposite ?l) (getQ ?state'2)) (getF ?state'2) (getM ?state'2)
      using ‹set (getQ ?stateB) = set (removeAll (opposite ?l) (getQ ?state'2))
      using ‹getConflictFlag ?stateB = getConflictFlag ?state'2
      using ‹getF ?stateB = getF ?state'2
      using ‹getM ?stateB = getM ?state'2
      unfolding InvariantQCharacterization_def
      by (simp add: Let_def)
  next
    case True
    let ?state02 = "setReason (opposite (getCl state)) (length (getF state) - 1) 
                    stategetConflictFlag := False, getM := ?prefix"
    have  "InvariantWatchesEl (getF ?state02) (getWatch1 ?state02) (getWatch2 ?state02)"
      using ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)
      unfolding InvariantWatchesEl_def
      unfolding setReason_def
      by auto
    
    have "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state02) (getF ?state02)"
      using ‹InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)
      unfolding InvariantWatchListsContainOnlyClausesFromF_def
      unfolding setReason_def
      by auto


    let ?stateTmp' = "assertLiteral (opposite (getCl state)) False
      (setReason (opposite (getCl state)) (length (getF state) - 1) 
           state getConflictFlag := False,
                  getM := prefixToLevel (getBackjumpLevel state) (getM state),
                  getQ := []
      )"
    let ?stateTmp'' = "assertLiteral (opposite (getCl state)) False
     (setReason (opposite (getCl state)) (length (getF state) - 1) 
          state  getConflictFlag := False,
                  getM := prefixToLevel (getBackjumpLevel state) (getM state),
                  getQ := [opposite (getCl state)]
     )"

    have "getM ?stateTmp' = getM ?stateTmp''"
         "getF ?stateTmp' = getF ?stateTmp''"
         "getSATFlag ?stateTmp' = getSATFlag ?stateTmp''"
         "getConflictFlag ?stateTmp' = getConflictFlag ?stateTmp''"
      using AssertLiteralStartQIreleveant[of "?state02" "opposite ?l" "False" "[]" "[opposite ?l]"]
      using ‹InvariantWatchesEl (getF ?state02) (getWatch1 ?state02) (getWatch2 ?state02)
      using ‹InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state02) (getF ?state02)
      by (auto simp add: Let_def)
    moreover
    have "?stateB = ?stateTmp'"
      using ‹getBackjumpLevel state > 0
      using arg_cong[of "state 
                               getConflictFlag := False,
                               getQ := [],
                               getM := ?prefix,
                               getReason := getReason state(opposite ?l  length (getF state) - 1)
                               "
                        "state 
                               getReason := getReason state(opposite ?l  length (getF state) - 1),
                               getConflictFlag := False, 
                               getM := prefixToLevel (getBackjumpLevel state) (getM state),
                               getQ := []
                               "
                        "λ x. assertLiteral (opposite ?l) False x"]
      unfolding applyBackjump_def
      unfolding setReason_def
      by (auto simp add: Let_def)
    moreover
    have "?stateTmp'' = ?state''2"
      unfolding setReason_def
      using arg_cong[of "state getReason := getReason state(opposite ?l  length (getF state) - 1), 
                               getConflictFlag := False,
                               getM := ?prefix, getQ := [opposite ?l]"
                        "state getConflictFlag := False, 
                               getM := prefixToLevel (getBackjumpLevel state) (getM state),
                               getReason := getReason state(opposite ?l  length (getF state) - 1),
                               getQ := [opposite ?l]"
                        "λ x. assertLiteral (opposite ?l) False x"]
      by simp
    ultimately 
    have "getConflictFlag ?stateB = getConflictFlag ?state''2" 
      "getF ?stateB = getF ?state''2"  
      "getM ?stateB = getM ?state''2"
      by auto

    have  "set (getQ ?stateB) = set (removeAll (opposite ?l) (getQ ?state''2))"
    proof-
      have "set (getQ ?stateB) = set(getQ ?state''2) - {opposite ?l}"
      proof-
        let ?ulSet = "{ ul. ( uc. uc el (getF ?state''1)  
                                   ?l el uc  
                                   isUnitClause uc ul ((elements (getM ?state''1)) @ [opposite ?l])) }"
        have "set (getQ ?state''2) = {opposite ?l}  ?ulSet"
          using assertLiteralQEffect[of "?state''1" "opposite ?l" "False"]
          using assms
          using ‹InvariantConsistent (?prefix @  [(opposite ?l, False)])
          using ‹InvariantUniq (?prefix @  [(opposite ?l, False)])
          using ‹InvariantWatchCharacterization (getF ?state''1) (getWatch1 ?state''1) (getWatch2 ?state''1) (getM ?state''1)
          unfolding setReason_def
          by (simp add:Let_def)
        moreover
        have "set (getQ ?stateB) = ?ulSet"
          using assertLiteralQEffect[of "?state''" "opposite ?l" "False"]
          using assms
          using ‹InvariantConsistent (?prefix @  [(opposite ?l, False)])
          using ‹InvariantUniq (?prefix @  [(opposite ?l, False)])
          using ‹InvariantWatchCharacterization (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') (getM ?state'')
          using ‹getBackjumpLevel state > 0
          unfolding applyBackjump_def
          unfolding setReason_def
          by (simp add:Let_def)
        moreover
        have "¬ (opposite ?l)  ?ulSet"
          using assertedLiteralIsNotUnit[of "?state''" "opposite ?l" "False"]
          using assms
          using ‹InvariantConsistent (?prefix @  [(opposite ?l, False)])
          using ‹InvariantUniq (?prefix @  [(opposite ?l, False)])
          using ‹InvariantWatchCharacterization (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') (getM ?state'')
          using ‹set (getQ ?stateB) = ?ulSet
          using ‹getBackjumpLevel state > 0
          unfolding applyBackjump_def
          unfolding setReason_def
          by (simp add: Let_def)
        ultimately
        show ?thesis
          by simp
      qed
      thus ?thesis
        by simp
    qed

    show ?thesis
      using ‹InvariantQCharacterization (getConflictFlag ?state''2) (removeAll (opposite ?l) (getQ ?state''2)) (getF ?state''2) (getM ?state''2)
      using ‹set (getQ ?stateB) = set (removeAll (opposite ?l) (getQ ?state''2))
      using ‹getConflictFlag ?stateB = getConflictFlag ?state''2
      using ‹getF ?stateB = getF ?state''2
      using ‹getM ?stateB = getM ?state''2
      unfolding InvariantQCharacterization_def
      by (simp add: Let_def)
  qed
qed

lemma InvariantConflictFlagCharacterizationAfterApplyBackjump_1:
assumes
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)" and

  "InvariantUniqC (getC state)"
  "getC state = [opposite (getCl state)]"
  "InvariantNoDecisionsWhenConflict (getF state) (getM state) (currentLevel (getM state))"

  "getConflictFlag state"
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)" and
  "InvariantCEntailed (getConflictFlag state) F0 (getC state)" and
  "InvariantClCharacterization (getCl state) (getC state) (getM state)" and
  "InvariantCllCharacterization (getCl state) (getCll state) (getC state) (getM state)" and
  "InvariantClCurrentLevel (getCl state) (getM state)"

  "currentLevel (getM state) > 0"
  "isUIP (opposite (getCl state)) (getC state) (getM state)"
shows
  "let state' = (applyBackjump state) in
     InvariantConflictFlagCharacterization (getConflictFlag state') (getF state') (getM state')"
proof-
  let ?l = "getCl state"
  let ?level = "getBackjumpLevel state"
  let ?prefix = "prefixToLevel ?level (getM state)"
  let ?state' = "state getConflictFlag := False, getQ := [], getM := ?prefix "
  let ?state'' = "setReason (opposite ?l) (length (getF state) - 1) ?state'"
  let ?stateB = "applyBackjump state"

  have "?level < elementLevel ?l (getM state)"
    using assms
    using isMinimalBackjumpLevelGetBackjumpLevel[of "state"]
    unfolding isMinimalBackjumpLevel_def
    unfolding isBackjumpLevel_def
    by (simp add: Let_def)
  hence "?level < currentLevel (getM state)"
    using elementLevelLeqCurrentLevel[of "?l" "getM state"]
    by simp
  hence "InvariantConflictFlagCharacterization (getConflictFlag ?state') (getF ?state') (getM ?state')"
    using ‹InvariantNoDecisionsWhenConflict (getF state) (getM state) (currentLevel (getM state))
    unfolding InvariantNoDecisionsWhenConflict_def
    unfolding InvariantConflictFlagCharacterization_def
    by simp
  moreover
  have "InvariantConsistent (?prefix @ [(opposite ?l, False)])"
    using assms
    using InvariantConsistentAfterApplyBackjump[of "state" "F0"]
    using assertLiteralEffect
    unfolding applyBackjump_def
    unfolding setReason_def
    by (auto simp add: Let_def split: if_split_asm)
  ultimately
  show ?thesis
    using InvariantConflictFlagCharacterizationAfterAssertLiteral[of "?state'"]
    using InvariantConflictFlagCharacterizationAfterAssertLiteral[of "?state''"]
    using InvariantWatchCharacterizationInBackjumpPrefix[of "state"]
    using assms
    unfolding applyBackjump_def
    unfolding setReason_def
    using assertLiteralEffect
    by (auto simp add: Let_def)
qed


lemma InvariantConflictFlagCharacterizationAfterApplyBackjump_2:
assumes
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)" and

  "InvariantUniqC (getC state)"
  "getC state  [opposite (getCl state)]"
  "InvariantNoDecisionsWhenConflict (butlast (getF state)) (getM state) (currentLevel (getM state))"
  "getF state  []" "last (getF state) = getC state"

  "getConflictFlag state"
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)" and
  "InvariantCEntailed (getConflictFlag state) F0 (getC state)" and
  "InvariantClCharacterization (getCl state) (getC state) (getM state)" and
  "InvariantCllCharacterization (getCl state) (getCll state) (getC state) (getM state)" and
  "InvariantClCurrentLevel (getCl state) (getM state)"

  "currentLevel (getM state) > 0"
  "isUIP (opposite (getCl state)) (getC state) (getM state)"
shows
  "let state' = (applyBackjump state) in
     InvariantConflictFlagCharacterization (getConflictFlag state') (getF state') (getM state')"
proof-
  let ?l = "getCl state"
  let ?level = "getBackjumpLevel state"
  let ?prefix = "prefixToLevel ?level (getM state)"
  let ?state' = "state getConflictFlag := False, getQ := [], getM := ?prefix "
  let ?state'' = "setReason (opposite ?l) (length (getF state) - 1) ?state'"
  let ?stateB = "applyBackjump state"

  have "?level < elementLevel ?l (getM state)"
    using assms
    using isMinimalBackjumpLevelGetBackjumpLevel[of "state"]
    unfolding isMinimalBackjumpLevel_def
    unfolding isBackjumpLevel_def
    by (simp add: Let_def)
  hence "?level < currentLevel (getM state)"
    using elementLevelLeqCurrentLevel[of "?l" "getM state"]
    by simp

  hence "InvariantConflictFlagCharacterization (getConflictFlag ?state') (butlast (getF ?state')) (getM ?state')"
    using ‹InvariantNoDecisionsWhenConflict (butlast (getF state)) (getM state) (currentLevel (getM state))
    unfolding InvariantNoDecisionsWhenConflict_def
    unfolding InvariantConflictFlagCharacterization_def
    by simp
  moreover
  have "isBackjumpLevel (getBackjumpLevel state) (opposite (getCl state)) (getC state) (getM state)"
    using assms
    using isMinimalBackjumpLevelGetBackjumpLevel[of "state"]
    unfolding isMinimalBackjumpLevel_def
    by (simp add: Let_def)
  hence "isUnitClause (last (getF state)) (opposite ?l) (elements ?prefix)"
    using isBackjumpLevelEnsuresIsUnitInPrefix[of "getM state" "getC state" "getBackjumpLevel state" "opposite ?l"]
    using ‹InvariantUniq (getM state)
    using ‹InvariantConsistent (getM state)
    using ‹getConflictFlag state
    using ‹InvariantCFalse (getConflictFlag state) (getM state) (getC state)
    using ‹last (getF state) = getC state
    unfolding InvariantUniq_def
    unfolding InvariantConsistent_def
    unfolding InvariantCFalse_def
    by (simp add: Let_def)
  hence "¬ clauseFalse (last (getF state)) (elements ?prefix)"
    unfolding isUnitClause_def
    by (auto simp add: clauseFalseIffAllLiteralsAreFalse)
  moreover
  from ‹getF state  []
  have "butlast (getF state) @ [last (getF state)] = getF state"
    using append_butlast_last_id[of "getF state"]
    by simp
  hence "getF state = butlast (getF state) @ [last (getF state)]"
    by (rule sym)
  ultimately
  have "InvariantConflictFlagCharacterization (getConflictFlag ?state') (getF ?state') (getM ?state')"
    using set_append[of "butlast (getF state)" "[last (getF state)]"]
    unfolding InvariantConflictFlagCharacterization_def
    by (auto simp add: formulaFalseIffContainsFalseClause)
  moreover
  have "InvariantConsistent (?prefix @ [(opposite ?l, False)])"
    using assms
    using InvariantConsistentAfterApplyBackjump[of "state" "F0"]
    using assertLiteralEffect
    unfolding applyBackjump_def
    unfolding setReason_def
    by (auto simp add: Let_def split: if_split_asm)
  ultimately
  show ?thesis
    using InvariantConflictFlagCharacterizationAfterAssertLiteral[of "?state'"]
    using InvariantConflictFlagCharacterizationAfterAssertLiteral[of "?state''"]
    using InvariantWatchCharacterizationInBackjumpPrefix[of "state"]
    using assms
    using assertLiteralEffect
    unfolding applyBackjump_def
    unfolding setReason_def
    by (auto simp add: Let_def)
qed

lemma InvariantConflictClauseCharacterizationAfterApplyBackjump:
assumes
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)"
shows
  "let state' = applyBackjump state in
      InvariantConflictClauseCharacterization (getConflictFlag state') (getConflictClause state') (getF state') (getM state')"
proof-
  let ?l = "getCl state"
  let ?level = "getBackjumpLevel state"
  let ?prefix = "prefixToLevel ?level (getM state)"
  let ?state' = "state getConflictFlag := False, getQ := [], getM := ?prefix "
  let ?state'' = "if 0 < ?level then setReason (opposite ?l) (length (getF state) - 1) ?state' else ?state'"

  have "¬ getConflictFlag ?state'"
    by simp
  hence "InvariantConflictClauseCharacterization (getConflictFlag ?state'') (getConflictClause ?state'') (getF ?state'') (getM ?state'')"
    unfolding InvariantConflictClauseCharacterization_def
    unfolding setReason_def
    by auto
  moreover
  have "getF ?state'' = getF state" 
    "getWatchList ?state'' = getWatchList state"
    "getWatch1 ?state'' = getWatch1 state"
    "getWatch2 ?state'' = getWatch2 state"
    unfolding setReason_def
    by auto
  ultimately
  show ?thesis
    using assms
    using InvariantConflictClauseCharacterizationAfterAssertLiteral[of "?state''"]
    unfolding applyBackjump_def
    by (simp only: Let_def)
qed

lemma InvariantGetReasonIsReasonAfterApplyBackjump:
assumes
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)" and
  "getConflictFlag state"
  "InvariantUniqC (getC state)"
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)"
  "InvariantCEntailed (getConflictFlag state) F0 (getC state)"
  "InvariantClCharacterization (getCl state) (getC state) (getM state)"
  "InvariantCllCharacterization (getCl state) (getCll state) (getC state) (getM state)"
  "InvariantClCurrentLevel (getCl state) (getM state)"
  "isUIP (opposite (getCl state)) (getC state) (getM state)"
  "0 < currentLevel (getM state)"
  "InvariantGetReasonIsReason (getReason state) (getF state) (getM state) (set (getQ state))"
  "getBackjumpLevel state > 0  getF state  []  last (getF state) = getC state"
shows
  "let state' = applyBackjump state in
    InvariantGetReasonIsReason (getReason state') (getF state') (getM state') (set (getQ state'))
  "
proof-
  let ?l = "getCl state"
  let ?level = "getBackjumpLevel state"
  let ?prefix = "prefixToLevel ?level (getM state)"
  let ?state' = "state getConflictFlag := False, getQ := [], getM := ?prefix "
  let ?state'' = "if 0 < ?level then setReason (opposite ?l) (length (getF state) - 1) ?state' else ?state'"
  let ?stateB = "applyBackjump state"
  have "InvariantGetReasonIsReason (getReason ?state') (getF ?state') (getM ?state') (set (getQ ?state'))"
  proof-
    {
      fix l::Literal
      assume *: "l el (elements ?prefix)  ¬ l el (decisions ?prefix)  elementLevel l ?prefix > 0"
      hence "l el (elements (getM state))  ¬ l el (decisions (getM state))  elementLevel l (getM state) > 0"
        using ‹InvariantUniq (getM state)
        unfolding InvariantUniq_def
        using isPrefixPrefixToLevel[of "?level" "(getM state)"]
        using isPrefixElements[of "?prefix" "getM state"]
        using prefixIsSubset[of "elements ?prefix" "elements (getM state)"]
        using markedElementsTrailMemPrefixAreMarkedElementsPrefix[of "getM state" "?prefix" "l"]
        using elementLevelPrefixElement[of "l" "getBackjumpLevel state" "getM state"]
        by auto
        
      with assms
      obtain reason
        where "reason < length (getF state)" "isReason (nth (getF state) reason) l (elements (getM state))"
        "getReason state l = Some reason"
        unfolding InvariantGetReasonIsReason_def
        by auto
      hence " reason. getReason state l = Some reason  
                       reason < length (getF state)  
                       isReason (nth (getF state) reason) l (elements ?prefix)"
        using isReasonHoldsInPrefix[of "l" "elements ?prefix" "elements (getM state)" "nth (getF state) reason"]
        using isPrefixPrefixToLevel[of "?level" "(getM state)"]
        using isPrefixElements[of "?prefix" "getM state"]
        using *
        by auto
    }
    thus ?thesis
      unfolding InvariantGetReasonIsReason_def
      by auto
  qed

  let ?stateM = "?state''  getM := getM ?state'' @ [(opposite ?l, False)] "


  have **: "getM ?stateM = ?prefix @ [(opposite ?l, False)]" 
    "getF ?stateM = getF state" 
    "getQ ?stateM = []"
    "getWatchList ?stateM = getWatchList state"
    "getWatch1 ?stateM = getWatch1 state"
    "getWatch2 ?stateM = getWatch2 state"
    unfolding setReason_def
    by auto

  have "InvariantGetReasonIsReason (getReason ?stateM) (getF ?stateM) (getM ?stateM) (set (getQ ?stateM))"
  proof-
    {
      fix l::Literal
      assume *: "l el (elements (getM ?stateM))  ¬ l el (decisions  (getM ?stateM))  elementLevel l  (getM ?stateM) > 0"

      have "isPrefix ?prefix (getM ?stateM)"
        unfolding setReason_def
        unfolding isPrefix_def
        by auto

      have " reason. getReason ?stateM l = Some reason  
                       reason < length (getF ?stateM)  
                       isReason (nth (getF ?stateM) reason) l (elements (getM ?stateM))"
      proof (cases "l = opposite ?l") 
        case False
        hence "l el (elements ?prefix)"
          using *
          using **
          by auto
        moreover
        hence "¬ l el (decisions ?prefix)"
          using elementLevelAppend[of "l" "?prefix" "[(opposite ?l, False)]"]
          using ‹isPrefix ?prefix (getM ?stateM)
          using markedElementsPrefixAreMarkedElementsTrail[of "?prefix" "getM ?stateM" "l"]
          using *
          using **
          by auto
        moreover
        have "elementLevel l ?prefix = elementLevel l (getM ?stateM)"
          using l el (elements ?prefix)
          using *
          using **
          using elementLevelAppend[of "l" "?prefix" "[(opposite ?l, False)]"]
          by auto
        hence "elementLevel l ?prefix > 0"
          using *
          by simp
        ultimately
        obtain reason
          where "reason < length (getF state)" 
          "isReason (nth (getF state) reason) l (elements ?prefix)"
          "getReason state l = Some reason"
          using ‹InvariantGetReasonIsReason (getReason ?state') (getF ?state') (getM ?state') (set (getQ ?state'))
          unfolding InvariantGetReasonIsReason_def
          by auto
        moreover
        have "getReason ?stateM l = getReason ?state' l"
          using False
          unfolding setReason_def
          by auto
        ultimately
        show ?thesis
          using isReasonAppend[of "nth (getF state) reason" "l" "elements ?prefix" "[opposite ?l]"]
          using **
          by auto
      next
        case True
        show ?thesis
        proof (cases "?level = 0")
          case True
          hence "currentLevel (getM ?stateM) = 0"
            using currentLevelPrefixToLevel[of "0" "getM state"]
            using *
            unfolding currentLevel_def
            by (simp add: markedElementsAppend)
          hence "elementLevel l (getM ?stateM) = 0"
            using ?level = 0
            using elementLevelLeqCurrentLevel[of "l" "getM ?stateM"]
            by simp
          with *
          have False
            by simp
          thus ?thesis
            by simp
        next
          case False
          let ?reason = "length (getF state) - 1"

          have "getReason ?stateM l = Some ?reason"
            using ?level  0
            using l = opposite ?l
            unfolding setReason_def
            by auto
          moreover
          have "(nth (getF state) ?reason) = (getC state)"
            using ?level  0
            using ‹getBackjumpLevel state > 0  getF state  []  last (getF state) = getC state
            using last_conv_nth[of "getF state"]
            by simp

          hence "isUnitClause (nth (getF state) ?reason) l (elements ?prefix)"
            using assms
            using applyBackjumpEffect[of "state" "F0"]
            using l = opposite ?l
            by (simp add: Let_def)
          hence "isReason (nth (getF state) ?reason) l (elements (getM ?stateM))"
            using **
            using isUnitClauseIsReason[of "nth (getF state) ?reason" "l" "elements ?prefix" "[opposite ?l]"]
            using l = opposite ?l
            by simp
          moreover
          have "?reason < length (getF state)"
            using ?level  0
            using ‹getBackjumpLevel state > 0  getF state  []  last (getF state) = getC state
            by simp
          ultimately
          show ?thesis
            using ?level  0
            using l = opposite ?l
            using **
            by auto
        qed
      qed
    }
    thus ?thesis
      unfolding InvariantGetReasonIsReason_def
      unfolding setReason_def
      by auto
  qed
  thus ?thesis
    using InvariantGetReasonIsReasonAfterNotifyWatches[of "?stateM" "getWatchList ?stateM ?l" "?l" "?prefix" "False" "{}" "[]"]
    unfolding applyBackjump_def
    unfolding Let_def
    unfolding assertLiteral_def
    unfolding Let_def
    unfolding notifyWatches_def
    using **
    using assms
    unfolding InvariantWatchListsCharacterization_def
    unfolding InvariantWatchListsUniq_def
    unfolding InvariantWatchListsContainOnlyClausesFromF_def
    by auto
qed


lemma InvariantsNoDecisionsWhenConflictNorUnitAfterApplyBackjump_1:
assumes 
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and

  "InvariantUniqC (getC state)"
  "getC state = [opposite (getCl state)]"

  "InvariantNoDecisionsWhenConflict (getF state) (getM state) (currentLevel (getM state))"
  "InvariantNoDecisionsWhenUnit (getF state) (getM state) (currentLevel (getM state))"
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)" and
  "InvariantCEntailed (getConflictFlag state) F0 (getC state)" and
  "InvariantClCharacterization (getCl state) (getC state) (getM state)" and
  "InvariantCllCharacterization (getCl state) (getCll state) (getC state) (getM state)" and
  "InvariantClCurrentLevel (getCl state) (getM state)"

  "getConflictFlag state"
  "isUIP (opposite (getCl state)) (getC state) (getM state)"
  "currentLevel (getM state) > 0"
shows 
  "let state' = applyBackjump state in 
          InvariantNoDecisionsWhenConflict (getF state') (getM state') (currentLevel (getM state'))  
          InvariantNoDecisionsWhenUnit (getF state') (getM state') (currentLevel (getM state'))"
proof-
  let ?l = "getCl state"
  let ?bClause = "getC state"
  let ?bLiteral = "opposite ?l"
  let ?level = "getBackjumpLevel state"
  let ?prefix = "prefixToLevel ?level (getM state)"
  let ?state' = "applyBackjump state"
  have "getM ?state' = ?prefix @ [(?bLiteral, False)]" "getF ?state' = getF state"
    using assms
    using applyBackjumpEffect[of "state"]
    by (auto simp add: Let_def)
  show ?thesis
  proof-
    
    have "?level < elementLevel ?l (getM state)"
      using assms
      using isMinimalBackjumpLevelGetBackjumpLevel[of "state"]
      unfolding isMinimalBackjumpLevel_def
      unfolding isBackjumpLevel_def
      by (simp add: Let_def)
    hence "?level < currentLevel (getM state)"
      using elementLevelLeqCurrentLevel[of "?l" "getM state"]
      by simp

    have "currentLevel (getM ?state') = currentLevel ?prefix"
      using ‹getM ?state' = ?prefix @ [(?bLiteral, False)]
      using markedElementsAppend[of "?prefix" "[(?bLiteral, False)]"]
      unfolding currentLevel_def
      by simp

    hence "currentLevel (getM ?state')  ?level"
      using currentLevelPrefixToLevel[of "?level" "getM state"]
      by simp

    show ?thesis
    proof-
      {
        fix level
        assume "level < currentLevel (getM ?state')"
        hence "level < currentLevel ?prefix"
          using ‹currentLevel (getM ?state') = currentLevel ?prefix
          by simp
        hence "prefixToLevel level (getM (applyBackjump state)) = prefixToLevel level ?prefix"
          using ‹getM ?state' = ?prefix @ [(?bLiteral, False)]
          using prefixToLevelAppend[of "level" "?prefix" "[(?bLiteral, False)]"]
          by simp
        have "level < ?level"
          using level < currentLevel ?prefix
          using ‹currentLevel (getM ?state')  ?level
          using ‹currentLevel (getM ?state') = currentLevel ?prefix
          by simp
        have "prefixToLevel level (getM ?state') = prefixToLevel level ?prefix"
          using ‹getM ?state' = ?prefix @ [(?bLiteral, False)]
          using prefixToLevelAppend[of "level" "?prefix" "[(?bLiteral, False)]"]
          using level < currentLevel ?prefix
          by simp

        hence "¬ formulaFalse (getF ?state') (elements (prefixToLevel level (getM ?state')))"  (is "?false")
          using ‹InvariantNoDecisionsWhenConflict (getF state) (getM state) (currentLevel (getM state))
          unfolding InvariantNoDecisionsWhenConflict_def
          using level < ?level
          using ?level < currentLevel (getM state)
          using prefixToLevelPrefixToLevelHigherLevel[of "level" "?level" "getM state", THEN sym]
          using ‹getF ?state' = getF state
          using ‹prefixToLevel level (getM ?state') = prefixToLevel level ?prefix
          using prefixToLevelPrefixToLevelHigherLevel[of "level" "?level" "getM state", THEN sym]
          by (auto simp add: formulaFalseIffContainsFalseClause)
        moreover
        have "¬ ( clause literal. 
                     clause el (getF ?state')  
                     isUnitClause clause literal (elements (prefixToLevel level (getM ?state'))))" (is "?unit")
          using ‹InvariantNoDecisionsWhenUnit  (getF state) (getM state) (currentLevel (getM state))
          unfolding InvariantNoDecisionsWhenUnit_def
          using level < ?level
          using ?level < currentLevel (getM state)
          using ‹getF ?state' = getF state
          using ‹prefixToLevel level (getM ?state') = prefixToLevel level ?prefix
          using prefixToLevelPrefixToLevelHigherLevel[of "level" "?level" "getM state", THEN sym]
          by simp
        ultimately
        have "?false  ?unit"
          by simp
      } 
      thus ?thesis
        unfolding InvariantNoDecisionsWhenConflict_def
        unfolding InvariantNoDecisionsWhenUnit_def
        by (auto simp add: Let_def)
    qed
  qed
qed


lemma InvariantsNoDecisionsWhenConflictNorUnitAfterApplyBackjump_2:
assumes 
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and

  "InvariantUniqC (getC state)"
  "getC state   [opposite (getCl state)]"
  "InvariantNoDecisionsWhenConflict (butlast (getF state)) (getM state) (currentLevel (getM state))"
  "InvariantNoDecisionsWhenUnit (butlast (getF state)) (getM state) (currentLevel (getM state))"
  "getF state  []" "last (getF state) = getC state"
  "InvariantNoDecisionsWhenConflict [getC state] (getM state) (getBackjumpLevel state)"
  "InvariantNoDecisionsWhenUnit [getC state] (getM state) (getBackjumpLevel state)"

  "getConflictFlag state"
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)" and
  "InvariantCEntailed (getConflictFlag state) F0 (getC state)" and
  "InvariantClCharacterization (getCl state) (getC state) (getM state)" and
  "InvariantCllCharacterization (getCl state) (getCll state) (getC state) (getM state)" and
  "InvariantClCurrentLevel (getCl state) (getM state)"

  "isUIP (opposite (getCl state)) (getC state) (getM state)"
  "currentLevel (getM state) > 0"
shows 
  "let state' = applyBackjump state in 
          InvariantNoDecisionsWhenConflict (getF state') (getM state') (currentLevel (getM state'))  
          InvariantNoDecisionsWhenUnit (getF state') (getM state') (currentLevel (getM state'))"
proof-
  let ?l = "getCl state"
  let ?bClause = "getC state"
  let ?bLiteral = "opposite ?l"
  let ?level = "getBackjumpLevel state"
  let ?prefix = "prefixToLevel ?level (getM state)"
  let ?state' = "applyBackjump state"
  have "getM ?state' = ?prefix @ [(?bLiteral, False)]" "getF ?state' = getF state"
    using assms
    using applyBackjumpEffect[of "state"]
    by (auto simp add: Let_def)
  show ?thesis
  proof-
    have "?level < elementLevel ?l (getM state)"
      using assms
      using isMinimalBackjumpLevelGetBackjumpLevel[of "state"]
      unfolding isMinimalBackjumpLevel_def
      unfolding isBackjumpLevel_def
      by (simp add: Let_def)
    hence "?level < currentLevel (getM state)"
      using elementLevelLeqCurrentLevel[of "?l" "getM state"]
      by simp

    have "currentLevel (getM ?state') = currentLevel ?prefix"
      using ‹getM ?state' = ?prefix @ [(?bLiteral, False)]
      using markedElementsAppend[of "?prefix" "[(?bLiteral, False)]"]
      unfolding currentLevel_def
      by simp

    hence "currentLevel (getM ?state')  ?level"
      using currentLevelPrefixToLevel[of "?level" "getM state"]
      by simp

    show ?thesis
    proof-
      {
        fix level
        assume "level < currentLevel (getM ?state')"
        hence "level < currentLevel ?prefix"
          using ‹currentLevel (getM ?state') = currentLevel ?prefix
          by simp
        hence "prefixToLevel level (getM (applyBackjump state)) = prefixToLevel level ?prefix"
          using ‹getM ?state' = ?prefix @ [(?bLiteral, False)]
          using prefixToLevelAppend[of "level" "?prefix" "[(?bLiteral, False)]"]
          by simp
        have "level < ?level"
          using level < currentLevel ?prefix
          using ‹currentLevel (getM ?state')  ?level
          using ‹currentLevel (getM ?state') = currentLevel ?prefix
          by simp
        have "prefixToLevel level (getM ?state') = prefixToLevel level ?prefix"
          using ‹getM ?state' = ?prefix @ [(?bLiteral, False)]
          using prefixToLevelAppend[of "level" "?prefix" "[(?bLiteral, False)]"]
          using level < currentLevel ?prefix
          by simp

        have "¬ formulaFalse (butlast (getF ?state')) (elements (prefixToLevel level (getM ?state')))" 
          using ‹getF ?state' = getF state
          using ‹InvariantNoDecisionsWhenConflict (butlast (getF state)) (getM state) (currentLevel (getM state))
          using level < ?level
          using ?level < currentLevel (getM state)
          using ‹prefixToLevel level (getM ?state') = prefixToLevel level ?prefix
          using prefixToLevelPrefixToLevelHigherLevel[of "level" "?level" "getM state", THEN sym]
          unfolding InvariantNoDecisionsWhenConflict_def
          by (auto simp add: formulaFalseIffContainsFalseClause)
        moreover
        have "¬ clauseFalse (last (getF ?state')) (elements (prefixToLevel level (getM ?state')))"
          using ‹getF ?state' = getF state
          using ‹InvariantNoDecisionsWhenConflict [getC state] (getM state) (getBackjumpLevel state)
          using ‹last (getF state) = getC state
          using level < ?level
          using ‹prefixToLevel level (getM ?state') = prefixToLevel level ?prefix
          using prefixToLevelPrefixToLevelHigherLevel[of "level" "?level" "getM state", THEN sym]
          unfolding InvariantNoDecisionsWhenConflict_def
          by (simp add: formulaFalseIffContainsFalseClause)
        moreover
        from ‹getF state  []
        have "butlast (getF state) @ [last (getF state)] = getF state"
          using append_butlast_last_id[of "getF state"]
          by simp
        hence "getF state = butlast (getF state) @ [last (getF state)]"
          by (rule sym)
        ultimately
        have "¬ formulaFalse (getF ?state') (elements (prefixToLevel level (getM ?state')))" (is "?false")
          using ‹getF ?state' = getF state
          using set_append[of "butlast (getF state)" "[last (getF state)]"]
          by (auto simp add: formulaFalseIffContainsFalseClause)
        
        have "¬ ( clause literal. 
          clause el (butlast (getF ?state'))  
          isUnitClause clause literal (elements (prefixToLevel level (getM ?state'))))"
          using ‹InvariantNoDecisionsWhenUnit (butlast (getF state)) (getM state) (currentLevel (getM state))
          unfolding InvariantNoDecisionsWhenUnit_def
          using level < ?level
          using ?level < currentLevel (getM state)
          using ‹getF ?state' = getF state
          using ‹prefixToLevel level (getM ?state') = prefixToLevel level ?prefix
          using prefixToLevelPrefixToLevelHigherLevel[of "level" "?level" "getM state", THEN sym]
          by simp
        moreover
        have "¬ ( l. isUnitClause (last (getF ?state')) l (elements (prefixToLevel level (getM ?state'))))"
          using ‹getF ?state' = getF state
          using ‹InvariantNoDecisionsWhenUnit [getC state] (getM state) (getBackjumpLevel state)
          using ‹last (getF state) = getC state
          using level < ?level
          using ‹prefixToLevel level (getM ?state') = prefixToLevel level ?prefix
          using prefixToLevelPrefixToLevelHigherLevel[of "level" "?level" "getM state", THEN sym]
          unfolding InvariantNoDecisionsWhenUnit_def
          by simp
        moreover
        from ‹getF state  []
        have "butlast (getF state) @ [last (getF state)] = getF state"
          using append_butlast_last_id[of "getF state"]
          by simp
        hence "getF state = butlast (getF state) @ [last (getF state)]"
          by (rule sym)
        ultimately
        have "¬ ( clause literal. 
                   clause el (getF ?state')  
                   isUnitClause clause literal (elements (prefixToLevel level (getM ?state'))))" (is ?unit)
          using ‹getF ?state' = getF state
          using set_append[of "butlast (getF state)" "[last (getF state)]"]
          by auto

        have "?false  ?unit"
          using ?false ?unit
          by simp
      } 
      thus ?thesis
        unfolding InvariantNoDecisionsWhenConflict_def
        unfolding InvariantNoDecisionsWhenUnit_def
        by (auto simp add: Let_def)
    qed
  qed
qed

lemma InvariantEquivalentZLAfterApplyBackjump:
assumes 
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and

  "getConflictFlag state"
  "InvariantUniqC (getC state)"
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)" and
  "InvariantCEntailed (getConflictFlag state) F0 (getC state)" and
  "InvariantClCharacterization (getCl state) (getC state) (getM state)" and
  "InvariantCllCharacterization (getCl state) (getCll state) (getC state) (getM state)" and
  "InvariantClCurrentLevel (getCl state) (getM state)"
  "InvariantEquivalentZL (getF state) (getM state) F0"

  "isUIP (opposite (getCl state)) (getC state) (getM state)"
  "currentLevel (getM state) > 0"
shows
  "let state' = applyBackjump state in
      InvariantEquivalentZL (getF state') (getM state') F0
  "
proof-
  
  let ?l = "getCl state"
  let ?bClause = "getC state"
  let ?bLiteral = "opposite ?l"
  let ?level = "getBackjumpLevel state"
  let ?prefix = "prefixToLevel ?level (getM state)"
  let ?state' = "applyBackjump state"
  
  have "formulaEntailsClause F0 ?bClause"
    "isUnitClause ?bClause ?bLiteral (elements ?prefix)"
    "getM ?state' = ?prefix @ [(?bLiteral, False)] "
    "getF ?state' = getF state"
    using assms
    using applyBackjumpEffect[of "state" "F0"]
    by (auto simp add: Let_def)
  note * = this
  show ?thesis
  proof (cases "?level = 0") 
    case False
    have "?level < elementLevel ?l (getM state)"
      using assms
      using isMinimalBackjumpLevelGetBackjumpLevel[of "state"]
      unfolding isMinimalBackjumpLevel_def
      unfolding isBackjumpLevel_def
      by (simp add: Let_def)
    hence "?level < currentLevel (getM state)"
      using elementLevelLeqCurrentLevel[of "?l" "getM state"]
      by simp
    hence "prefixToLevel 0 (getM ?state') = prefixToLevel 0 ?prefix"
      using *
      using prefixToLevelAppend[of "0" "?prefix" "[(?bLiteral, False)]"]
      using ?level  0
      using currentLevelPrefixToLevelEq[of "?level" "getM state"]
      by simp

    hence "prefixToLevel 0 (getM ?state') = prefixToLevel 0 (getM state)"
      using ?level  0
      using prefixToLevelPrefixToLevelHigherLevel[of "0" "?level" "getM state"]
      by simp
    thus ?thesis
      using *
      using ‹InvariantEquivalentZL (getF state) (getM state) F0
      unfolding InvariantEquivalentZL_def
      by (simp add: Let_def)    
  next
    case True
    hence "prefixToLevel 0 (getM ?state') = ?prefix @ [(?bLiteral, False)]"
      using *
      using prefixToLevelAppend[of "0" "?prefix" "[(?bLiteral, False)]"]
      using currentLevelPrefixToLevel[of "0" "getM state"]
      by simp

    let ?FM = "getF state @ val2form (elements (prefixToLevel 0 (getM state)))"
    let ?FM' = "getF ?state' @ val2form (elements (prefixToLevel 0 (getM ?state')))"
  
    have "formulaEntailsValuation F0 (elements ?prefix)"
      using ?level = 0
      using val2formIsEntailed[of "getF state" "elements (prefixToLevel 0 (getM state))" "[]"]
      using ‹InvariantEquivalentZL (getF state) (getM state) F0
      unfolding formulaEntailsValuation_def
      unfolding InvariantEquivalentZL_def
      unfolding equivalentFormulae_def
      unfolding formulaEntailsLiteral_def
      by auto

    have "formulaEntailsLiteral (F0 @ val2form (elements ?prefix)) ?bLiteral"
      using *
      using unitLiteralIsEntailed [of "?bClause" "?bLiteral" "elements ?prefix" "F0"]
      by simp

    have "formulaEntailsLiteral F0 ?bLiteral"
    proof-
      {
        fix valuation::Valuation
        assume "model valuation F0"
        hence "formulaTrue (val2form (elements ?prefix)) valuation"
          using ‹formulaEntailsValuation F0 (elements ?prefix)
          using val2formFormulaTrue[of "elements ?prefix" "valuation"]
          unfolding formulaEntailsValuation_def
          unfolding formulaEntailsLiteral_def
          by simp
        hence "formulaTrue (F0 @ (val2form (elements ?prefix))) valuation"
          using ‹model valuation F0
          by (simp add: formulaTrueAppend)
        hence "literalTrue ?bLiteral valuation"
          using ‹model valuation F0
          using ‹formulaEntailsLiteral (F0 @ val2form (elements ?prefix)) ?bLiteral
          unfolding formulaEntailsLiteral_def
          by auto
      }
      thus ?thesis
        unfolding formulaEntailsLiteral_def
        by simp
    qed
  
    hence "formulaEntailsClause F0 [?bLiteral]"
      unfolding formulaEntailsLiteral_def
      unfolding formulaEntailsClause_def
      by (auto simp add: clauseTrueIffContainsTrueLiteral)

    hence "formulaEntailsClause ?FM [?bLiteral]"
      using ‹InvariantEquivalentZL (getF state) (getM state) F0
      unfolding InvariantEquivalentZL_def
      unfolding equivalentFormulae_def
      unfolding formulaEntailsClause_def
      by auto
    
    have "?FM' = ?FM @ [[?bLiteral]]"
      using *
      using ?level = 0
      using ‹prefixToLevel 0 (getM ?state') = ?prefix @ [(?bLiteral, False)]
      by (auto simp add: val2formAppend)

    show ?thesis
      using ‹InvariantEquivalentZL (getF state) (getM state) F0
      using ?FM' = ?FM @ [[?bLiteral]]
      using ‹formulaEntailsClause ?FM [?bLiteral]
      unfolding InvariantEquivalentZL_def
      using extendEquivalentFormulaWithEntailedClause[of "F0" "?FM" "[?bLiteral]"]
      by (simp add: equivalentFormulaeSymmetry)
  qed
qed

lemma InvariantsVarsAfterApplyBackjump:
assumes 
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and

  "InvariantWatchListsUniq (getWatchList state)"
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)" and 

  "getConflictFlag state"
  "InvariantCFalse (getConflictFlag state) (getM state) (getC state)" and
  "InvariantUniqC (getC state)" and
  "InvariantCEntailed (getConflictFlag state) F0' (getC state)" and
  "InvariantClCharacterization (getCl state) (getC state) (getM state)" and
  "InvariantCllCharacterization (getCl state) (getCll state) (getC state) (getM state)" and
  "InvariantClCurrentLevel (getCl state) (getM state)"
  "InvariantEquivalentZL (getF state) (getM state) F0'"

  "isUIP (opposite (getCl state)) (getC state) (getM state)"
  "currentLevel (getM state) > 0"

  "vars F0'  vars F0"

  "InvariantVarsM (getM state) F0 Vbl"
  "InvariantVarsF (getF state) F0 Vbl"
  "InvariantVarsQ (getQ state) F0 Vbl"
shows
  "let state' = applyBackjump state in
      InvariantVarsM (getM state') F0 Vbl  
      InvariantVarsF (getF state') F0 Vbl  
      InvariantVarsQ (getQ state') F0 Vbl 
  "
proof-
  
  let ?l = "getCl state"
  let ?bClause = "getC state"
  let ?bLiteral = "opposite ?l"
  let ?level = "getBackjumpLevel state"
  let ?prefix = "prefixToLevel ?level (getM state)"
  let ?state' = "state getConflictFlag := False, getQ := [], getM := ?prefix "
  let ?state'' = "setReason (opposite (getCl state)) (length (getF state) - 1) ?state'"
  let ?stateB = "applyBackjump state"
  
  have "formulaEntailsClause F0' ?bClause"
    "isUnitClause ?bClause ?bLiteral (elements ?prefix)"
    "getM ?stateB = ?prefix @ [(?bLiteral, False)] "
    "getF ?stateB = getF state"
    using assms
    using applyBackjumpEffect[of "state" "F0'"]
    by (auto simp add: Let_def)
  note * = this

  have "var ?bLiteral  vars F0  Vbl"
  proof-
    have "vars (getC state)  vars (elements (getM state))"
      using ‹getConflictFlag state
      using ‹InvariantCFalse (getConflictFlag state) (getM state) (getC state)
      using valuationContainsItsFalseClausesVariables[of "getC state" "elements (getM state)"]
      unfolding InvariantCFalse_def
      by simp
    moreover
    have "?bLiteral el (getC state)"
      using ‹InvariantClCharacterization (getCl state) (getC state) (getM state)
      unfolding InvariantClCharacterization_def
      unfolding isLastAssertedLiteral_def
      using literalElListIffOppositeLiteralElOppositeLiteralList[of "?bLiteral" "getC state"]
      by simp
    ultimately
    show ?thesis
      using ‹InvariantVarsM (getM state) F0 Vbl
      using ‹vars F0'  vars F0
      unfolding InvariantVarsM_def
      using clauseContainsItsLiteralsVariable[of "?bLiteral" "getC state"]
      by auto
  qed

  hence "InvariantVarsM (getM ?stateB) F0 Vbl"
    using ‹InvariantVarsM (getM state) F0 Vbl
    using InvariantVarsMAfterBackjump[of "getM state" "F0" "Vbl" "?prefix" "?bLiteral" "getM ?stateB"]
    using *
    by (simp add: isPrefixPrefixToLevel)
  moreover
  have "InvariantConsistent (prefixToLevel (getBackjumpLevel state) (getM state) @ [(opposite (getCl state), False)])"
    "InvariantUniq (prefixToLevel (getBackjumpLevel state) (getM state) @ [(opposite (getCl state), False)])"
    "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (prefixToLevel (getBackjumpLevel state) (getM state))"
    using assms
    using InvariantConsistentAfterApplyBackjump[of "state" "F0'"]
    using InvariantUniqAfterApplyBackjump[of "state" "F0'"]
    using *
    using InvariantWatchCharacterizationInBackjumpPrefix[of "state"]
    by (auto simp add: Let_def)
  hence "InvariantVarsQ (getQ ?stateB) F0 Vbl"
    using ‹InvariantVarsF (getF state) F0 Vbl
    using ‹InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)
    using ‹InvariantWatchListsUniq (getWatchList state)
    using ‹InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)
    using ‹InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)
    using ‹InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)
    using InvariantVarsQAfterAssertLiteral[of "if ?level > 0 then ?state'' else ?state'" "?bLiteral" "False" "F0" "Vbl"]
    unfolding applyBackjump_def
    unfolding InvariantVarsQ_def
    unfolding setReason_def
    by (auto simp add: Let_def)
  moreover
  have "InvariantVarsF (getF ?stateB) F0 Vbl"
    using assms
    using assertLiteralEffect[of "if ?level > 0 then ?state'' else ?state'" "?bLiteral" "False"]
    using ‹InvariantVarsF (getF state) F0 Vbl
    unfolding applyBackjump_def
    unfolding setReason_def
    by (simp add: Let_def)
  ultimately
  show ?thesis
    by (simp add: Let_def)
qed

end

Theory Decide

(*    Title:              SatSolverVerification/Decide.thy
      Author:             Filip Maric
      Maintainer:         Filip Maric <filip at matf.bg.ac.yu>
*)

theory Decide
imports AssertLiteral
begin

(******************************************************************************)
(*          A P P L Y     D E C I D E                                         *)
(******************************************************************************)   

lemma applyDecideEffect:
assumes 
  "¬ vars(elements (getM state))  Vbl" and
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)"
shows 
  "let literal = selectLiteral state Vbl in 
   let state' = applyDecide state Vbl in 
          var literal  vars (elements (getM state))  
          var literal  Vbl  
          getM state' = getM state @ [(literal, True)]  
          getF state' = getF state"
using assms
using selectLiteral_def[of "Vbl" "state"]
unfolding applyDecide_def
using assertLiteralEffect[of "state" "selectLiteral state Vbl" "True"]
by (simp add: Let_def)

lemma InvariantConsistentAfterApplyDecide:
assumes 
  "¬ vars(elements (getM state))  Vbl" and
  "InvariantConsistent (getM state)" and
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)"
shows
  "let state' = applyDecide state Vbl in
         InvariantConsistent (getM state')"
using assms
using applyDecideEffect[of "Vbl" "state"]
using InvariantConsistentAfterDecide[of "getM state" "selectLiteral state Vbl" "getM (applyDecide state Vbl)"]
by (simp add: Let_def)


lemma InvariantUniqAfterApplyDecide:
assumes 
  "¬ vars(elements (getM state))  Vbl" and
  "InvariantUniq (getM state)" and
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)"
shows
  "let state' = applyDecide state Vbl in
         InvariantUniq (getM state')"
using assms
using applyDecideEffect[of "Vbl" "state"]
using InvariantUniqAfterDecide[of "getM state" "selectLiteral state Vbl" "getM (applyDecide state Vbl)"]
by (simp add: Let_def)

lemma InvariantQCharacterizationAfterApplyDecide:
assumes 
  "¬ vars(elements (getM state))  Vbl" and

  "InvariantConsistent (getM state)" and
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)"
  "InvariantWatchListsUniq (getWatchList state)"
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)"
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"

  "getQ state = []"
shows
  "let state' = applyDecide state Vbl in
     InvariantQCharacterization (getConflictFlag state') (getQ state') (getF state') (getM state')"
proof-
  let ?state' = "applyDecide state Vbl"
  let ?literal = "selectLiteral state Vbl"
  have "getM ?state' = getM state @ [(?literal, True)]"
    using assms
    using applyDecideEffect[of "Vbl" "state"]
    by (simp add: Let_def)
  hence "InvariantConsistent (getM state @ [(?literal, True)])"
    using InvariantConsistentAfterApplyDecide[of "Vbl" "state"]
    using assms
    by (simp add: Let_def)
  thus ?thesis
    using assms
    using InvariantQCharacterizationAfterAssertLiteralNotInQ[of "state" "?literal" "True"]
    unfolding applyDecide_def
    by simp
qed

lemma InvariantEquivalentZLAfterApplyDecide:
assumes
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantEquivalentZL (getF state) (getM state) F0"
shows
  "let state' = applyDecide state Vbl in
     InvariantEquivalentZL (getF state') (getM state') F0"
proof-
  let ?state' = "applyDecide state Vbl"
  let ?l = "selectLiteral state Vbl"

  have "getM ?state' = getM state @ [(?l, True)]"
    "getF ?state' = getF state"
    unfolding applyDecide_def
    using assertLiteralEffect[of "state" "?l" "True"]
    using assms
    by (auto simp only: Let_def)
  have "prefixToLevel 0 (getM ?state') = prefixToLevel 0 (getM state)"
  proof (cases "currentLevel (getM state) > 0")
    case True
    thus ?thesis
      using prefixToLevelAppend[of "0" "getM state" "[(?l, True)]"]
      using ‹getM ?state' = getM state @ [(?l, True)]
      by auto
  next
    case False
    hence "prefixToLevel 0 (getM state @ [(?l, True)]) = 
             getM state @ (prefixToLevel_aux [(?l, True)] 0 (currentLevel (getM state)))"
      using prefixToLevelAppend[of "0" "getM state" "[(?l, True)]"]
      by simp
    hence "prefixToLevel 0 (getM state @ [(?l, True)]) = getM state"
      by simp
    thus ?thesis
      using ‹getM ?state' = getM state @ [(?l, True)]
      using currentLevelZeroTrailEqualsItsPrefixToLevelZero[of "getM state"]
      using False
      by simp
  qed
  thus ?thesis
    using ‹InvariantEquivalentZL (getF state) (getM state) F0
    unfolding InvariantEquivalentZL_def
    using ‹getF ?state' = getF state
    by simp
qed


lemma InvariantGetReasonIsReasonAfterApplyDecide:
assumes
  "¬ vars (elements (getM state))  Vbl"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)"
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchListsUniq (getWatchList state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantGetReasonIsReason (getReason state) (getF state) (getM state) (set (getQ state))"
  "getQ state = []"
shows
  "let state' = applyDecide state Vbl in 
    InvariantGetReasonIsReason (getReason state') (getF state') (getM state') (set (getQ state'))"
proof-
  let ?l = "selectLiteral state Vbl"
  let ?stateM = "state  getM := getM state @ [(?l, True)] "
  have "InvariantGetReasonIsReason (getReason ?stateM) (getF ?stateM) (getM ?stateM) (set (getQ ?stateM))"
  proof-
    {
      fix l::Literal
      assume *: "l el (elements (getM ?stateM))" "¬ l el (decisions (getM ?stateM))" "elementLevel l (getM ?stateM) > 0"
      have " reason. getReason ?stateM l = Some reason 
        0  reason  reason < length (getF ?stateM) 
        isReason (getF ?stateM ! reason) l (elements (getM ?stateM))"
      proof (cases "l el (elements (getM state))")
        case True
        moreover
        hence "¬ l el (decisions (getM state))"
          using *
          by (simp add: markedElementsAppend)
        moreover
        have "elementLevel l (getM state) > 0"
        proof-
          {
            assume "¬ ?thesis"
            with *
            have "l = ?l"
              using True
              using elementLevelAppend[of "l" "getM state" "[(?l, True)]"]
              by simp
            hence "var ?l  vars (elements (getM state))"
              using True
              using valuationContainsItsLiteralsVariable[of "l" "elements (getM state)"]
              by simp
            hence False
              using ¬ vars (elements (getM state))  Vbl
              using selectLiteral_def[of "Vbl" "state"]
              by auto
          } thus ?thesis
            by auto
        qed
        ultimately
        obtain reason
          where "getReason state l = Some reason 
          0  reason  reason < length (getF state) 
          isReason (getF state ! reason) l (elements (getM state))"
          using ‹InvariantGetReasonIsReason (getReason state) (getF state) (getM state) (set (getQ state))
          unfolding InvariantGetReasonIsReason_def
          by auto
        thus ?thesis
          using isReasonAppend[of "nth (getF ?stateM) reason" "l" "elements (getM state)" "[?l]"]
          by auto
      next
        case False
        hence "l = ?l"
          using *
          by auto
        hence "l el (decisions (getM ?stateM))"
          using markedElementIsMarkedTrue[of "l" "getM ?stateM"]
          by auto
        with *
        have False
          by auto
        thus ?thesis
          by simp
      qed
    }
    thus ?thesis
      using ‹getQ state = []
      unfolding InvariantGetReasonIsReason_def
      by auto
  qed
  thus ?thesis
    using assms
    using InvariantGetReasonIsReasonAfterNotifyWatches[of "?stateM" "getWatchList ?stateM (opposite ?l)"
      "opposite ?l" "getM state" "True" "{}" "[]"]
    unfolding applyDecide_def
    unfolding assertLiteral_def
    unfolding notifyWatches_def
    unfolding InvariantWatchListsCharacterization_def
    unfolding InvariantWatchListsContainOnlyClausesFromF_def
    unfolding InvariantWatchListsUniq_def
    using ‹getQ state = []
    by (simp add: Let_def)
qed

lemma InvariantsVarsAfterApplyDecide:
assumes
  "¬ vars (elements (getM state))  Vbl"
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)"
  "InvariantWatchListsUniq (getWatchList state)"
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"

  "InvariantVarsM (getM state) F0 Vbl"
  "InvariantVarsF (getF state) F0 Vbl"
  "getQ state = []"
shows
  "let state' = applyDecide state Vbl in 
     InvariantVarsM (getM state') F0 Vbl  
     InvariantVarsF (getF state') F0 Vbl  
     InvariantVarsQ (getQ state') F0 Vbl"
proof-
  let ?state' = "applyDecide state Vbl"
  let ?l = "selectLiteral state Vbl"

  have "InvariantVarsM (getM ?state') F0 Vbl" "InvariantVarsF (getF ?state') F0 Vbl"
    using assms
    using applyDecideEffect[of "Vbl" "state"]
    using varsAppendValuation[of "elements (getM state)" "[?l]"]
    unfolding InvariantVarsM_def
    by (auto simp add: Let_def)
  moreover
  have "InvariantVarsQ (getQ ?state') F0 Vbl"
    using InvariantVarsQAfterAssertLiteral[of "state" "?l" "True" "F0" "Vbl"]
    using assms
    using InvariantConsistentAfterApplyDecide[of "Vbl" "state"]
    using InvariantUniqAfterApplyDecide[of "Vbl" "state"]
    using assertLiteralEffect[of "state" "?l" "True"]
    unfolding applyDecide_def
    unfolding InvariantVarsQ_def
    by (simp add: Let_def)
  ultimately
  show ?thesis
    by (simp add: Let_def)
qed

end

Theory SolveLoop

(*    Title:              SatSolverVerification/SolveLoop.thy
      Author:             Filip Maric
      Maintainer:         Filip Maric <filip at matf.bg.ac.yu>
*)

theory SolveLoop
imports UnitPropagate ConflictAnalysis Decide
begin


(******************************************************************************)
(*          S O L V E   L O O P   B O D Y                                     *)
(******************************************************************************)

lemma soundnessForUNSAT:
assumes 
  "equivalentFormulae (F @ val2form M) F0"
  "formulaFalse F M"
shows
  "¬ satisfiable F0"
proof-
  have "formulaEntailsValuation (F @ val2form M) M"
    using val2formIsEntailed[of "F" "M" "[]"]
    by simp
  moreover
  have "formulaFalse (F @ val2form M) M"
    using ‹formulaFalse F M
    by (simp add: formulaFalseAppend)
  ultimately
  have "¬ satisfiable (F @ val2form M)"
    using formulaFalseInEntailedValuationIsUnsatisfiable[of "F @ val2form M" "M"]
    by simp
  thus ?thesis
    using ‹equivalentFormulae (F @ val2form M) F0
    by (simp add: satisfiableEquivalent)
qed

lemma soundnessForSat:
  fixes F0 :: Formula and F :: Formula and M::LiteralTrail
  assumes "vars F0  Vbl" and "InvariantVarsF F F0 Vbl" and "InvariantConsistent M" and "InvariantEquivalentZL F M F0" and
  "¬ formulaFalse F (elements M)" and "vars (elements M)  Vbl"
  shows "model (elements M) F0"
proof-
  from ‹InvariantConsistent M
  have "consistent (elements M)"
    unfolding InvariantConsistent_def
    .
  moreover
  from ‹InvariantVarsF F F0 Vbl 
  have "vars F  vars F0  Vbl"
    unfolding InvariantVarsF_def
    .
  with ‹vars F0  Vbl 
  have "vars F  Vbl"
    by auto
  with ‹vars (elements M)  Vbl
  have "vars F  vars (elements M)"
    by simp
  hence "formulaTrue F (elements M)  formulaFalse F (elements M)"
    by (simp add:totalValuationForFormulaDefinesItsValue)
  with ¬ formulaFalse F (elements M)
  have "formulaTrue F (elements M)"
    by simp
  ultimately
  have "model (elements M) F"
    by simp
  moreover
  obtain s
    where "elements (prefixToLevel 0 M) @ s = elements M"
    using isPrefixPrefixToLevel[of "0" "M"]
    using isPrefixElements[of "prefixToLevel 0 M" "M"]
    unfolding isPrefix_def
    by auto
  hence "elements M = elements (prefixToLevel 0 M) @ s"
    by (rule sym)
  hence "formulaTrue (val2form (elements (prefixToLevel 0 M))) (elements M)"
    using val2formFormulaTrue[of "elements (prefixToLevel 0 M)" "elements M"]
    by auto
  hence "model (elements M) (val2form (elements (prefixToLevel 0 M)))"
    using ‹consistent (elements M)
    by simp
  ultimately
  show ?thesis
    using ‹InvariantEquivalentZL F M F0
    unfolding InvariantEquivalentZL_def
    unfolding equivalentFormulae_def
    using formulaTrueAppend[of "F" "val2form (elements (prefixToLevel 0 M))" "elements M"]
    by auto
qed

definition
"satFlagLessState = {(state1::State, state2::State). (getSATFlag state1)  UNDEF  (getSATFlag state2) = UNDEF}"


lemma wellFoundedSatFlagLessState:
  shows "wf satFlagLessState"
  unfolding wf_eq_minimal
proof-
  show "Q state. state  Q  (stateMinQ. state'. (state', stateMin)  satFlagLessState  state'  Q)"
  proof-
    {
      fix state::State and Q::"State set"
      assume "state  Q"
      have "stateMinQ. state'. (state', stateMin)  satFlagLessState  state'  Q"
      proof (cases " stateDef  Q. (getSATFlag stateDef)  UNDEF")
        case True
        then obtain stateDef where "stateDef  Q" "(getSATFlag stateDef)  UNDEF"
          by auto
        have "state'. (state', stateDef)  satFlagLessState  state'  Q"
        proof
          fix state'
          show "(state', stateDef)  satFlagLessState  state'  Q"
          proof
            assume "(state', stateDef)  satFlagLessState"
            hence "getSATFlag stateDef = UNDEF"
              unfolding satFlagLessState_def
              by auto
            with ‹getSATFlag stateDef  UNDEF› have False
              by simp
            thus "state'  Q"
              by simp
          qed
        qed
        with stateDef  Q
        show ?thesis
          by auto
      next
        case False
        have "state'. (state', state)  satFlagLessState  state'  Q"
        proof
          fix state'
          show "(state', state)  satFlagLessState  state'  Q"
          proof
            assume "(state', state)  satFlagLessState"
            hence "getSATFlag state'  UNDEF"
              unfolding satFlagLessState_def
              by simp
            with False
            show "state'  Q"
              by auto
          qed
        qed
        with state  Q 
        show ?thesis
          by auto
      qed
    }
    thus ?thesis
      by auto
  qed
qed

definition
"lexLessState1 Vbl = {(state1::State, state2::State). 
     getSATFlag state1 = UNDEF  getSATFlag state2 = UNDEF 
     (getM state1, getM state2)  lexLessRestricted Vbl
}"

lemma wellFoundedLexLessState1:
assumes
  "finite Vbl"
shows
  "wf (lexLessState1 Vbl)"
unfolding wf_eq_minimal
proof-
  show "Q state. state  Q  (stateMinQ. state'. (state', stateMin)  lexLessState1 Vbl  state'  Q)"
  proof-
    {
      fix Q :: "State set" and state :: State
      assume "state  Q"
      let ?Q1 = "{M::LiteralTrail.  state. state  Q  getSATFlag state = UNDEF  (getM state) = M}"
      have " stateMin  Q. (state'. (state', stateMin)  lexLessState1 Vbl  state'  Q)"
      proof (cases "?Q1  {}")
        case True
        then obtain M::LiteralTrail
          where "M  ?Q1"
          by auto
        then obtain MMin::LiteralTrail
          where "MMin  ?Q1" "M'. (M', MMin)  lexLessRestricted Vbl  M'  ?Q1"
          using wfLexLessRestricted[of "Vbl"] ‹finite Vbl
          unfolding wf_eq_minimal
          apply simp
          apply (erule_tac x="?Q1" in allE)
          by auto
        from MMin  ?Q1 obtain stateMin
          where "stateMin  Q" "(getM stateMin) = MMin" "getSATFlag stateMin = UNDEF"
          by auto
        have "state'. (state', stateMin)  lexLessState1 Vbl  state'  Q"
        proof
          fix state'
          show "(state', stateMin)  lexLessState1 Vbl  state'  Q"
          proof
            assume "(state', stateMin)  lexLessState1 Vbl"
            hence "getSATFlag state' = UNDEF" "(getM state', getM stateMin)  lexLessRestricted Vbl"
              unfolding lexLessState1_def
              by auto
            hence "getM state'  ?Q1"
              using M'. (M', MMin)  lexLessRestricted Vbl  M'  ?Q1
              using (getM stateMin) = MMin
              by auto
            thus "state'  Q"
              using ‹getSATFlag state' = UNDEF›
              by auto
          qed
        qed
        thus ?thesis
          using stateMin  Q
          by auto
      next
        case False
        have "state'. (state', state)  lexLessState1 Vbl  state'  Q"
        proof
          fix state'
          show "(state', state)  lexLessState1 Vbl  state'  Q"
          proof
            assume "(state', state)  lexLessState1 Vbl"
            hence "getSATFlag state = UNDEF"
              unfolding lexLessState1_def
              by simp
            hence "(getM state)  ?Q1"
              using state  Q
              by auto
            hence False
              using False
              by auto
            thus "state'  Q"
              by simp
          qed
        qed
        thus ?thesis
          using state  Q
          by auto
      qed
    }
    thus ?thesis
      by auto
  qed
qed

definition 
"terminationLessState1 Vbl = {(state1::State, state2::State). 
  (state1, state2)  satFlagLessState  
  (state1, state2)  lexLessState1 Vbl}"

lemma wellFoundedTerminationLessState1:
  assumes "finite Vbl"
  shows "wf (terminationLessState1 Vbl)"
unfolding wf_eq_minimal
proof-
  show " Q state. state  Q  ( stateMin  Q.  state'. (state', stateMin)  terminationLessState1 Vbl  state'  Q)"
  proof-
    {
      fix Q::"State set"
      fix state::"State"
      assume "state  Q"
      have "stateMinQ. state'. (state', stateMin)  terminationLessState1 Vbl  state'  Q"
      proof-
        obtain state0
          where "state0  Q" "state'. (state', state0)  satFlagLessState  state'  Q"
          using wellFoundedSatFlagLessState
          unfolding wf_eq_minimal
          using state  Q
          by auto
        show ?thesis
        proof (cases "getSATFlag state0 = UNDEF")
          case False
          hence "state'. (state', state0)  terminationLessState1 Vbl  state'  Q"
            using state'. (state', state0)  satFlagLessState  state'  Q
            unfolding terminationLessState1_def
            unfolding lexLessState1_def
            by simp
          thus ?thesis
            using state0  Q
            by auto
        next
          case True
          then obtain state1
            where "state1  Q" "state'. (state', state1)  lexLessState1 Vbl  state'  Q"
            using ‹finite Vbl
            using state  Q
            using wellFoundedLexLessState1[of "Vbl"]
            unfolding wf_eq_minimal
            by auto

          have "state'. (state', state1)  terminationLessState1 Vbl  state'  Q"
            using state'. (state', state1)  lexLessState1 Vbl  state'  Q
            unfolding terminationLessState1_def
            using state'. (state', state0)  satFlagLessState  state'  Q
            using True
            unfolding satFlagLessState_def
            by simp
          thus ?thesis
            using state1  Q
            by auto
        qed
      qed
    }
    thus ?thesis
      by auto
  qed
qed

lemma transTerminationLessState1:
  "trans (terminationLessState1 Vbl)"
proof-
  {
    fix x::State and y::State and z::State
    assume "(x, y)  terminationLessState1 Vbl" "(y, z)  terminationLessState1 Vbl"
    have "(x, z)  terminationLessState1 Vbl"
    proof (cases "(x, y)  satFlagLessState")
      case True
      hence "getSATFlag x  UNDEF" "getSATFlag y = UNDEF"
        unfolding satFlagLessState_def
        by auto
      hence "getSATFlag z = UNDEF"
        using (y, z)  terminationLessState1 Vbl
        unfolding terminationLessState1_def
        unfolding satFlagLessState_def
        unfolding lexLessState1_def
        by auto
      thus ?thesis
        using ‹getSATFlag x  UNDEF›
        unfolding terminationLessState1_def
        unfolding satFlagLessState_def
        by simp
    next
      case False
      with (x, y)  terminationLessState1 Vbl
      have "getSATFlag x = UNDEF" "getSATFlag y = UNDEF" "(getM x, getM y)  lexLessRestricted Vbl"
        unfolding terminationLessState1_def
        unfolding lexLessState1_def
        by auto
      hence "getSATFlag z = UNDEF" "(getM y, getM z)  lexLessRestricted Vbl"
        using (y, z)  terminationLessState1 Vbl
        unfolding terminationLessState1_def
        unfolding satFlagLessState_def
        unfolding lexLessState1_def
        by auto
      thus ?thesis
        using ‹getSATFlag x = UNDEF› 
        using (getM x, getM y)  lexLessRestricted Vbl
        using transLexLessRestricted[of "Vbl"]
        unfolding trans_def
        unfolding terminationLessState1_def
        unfolding satFlagLessState_def
        unfolding lexLessState1_def
        by blast
    qed
  }
  thus ?thesis
    unfolding trans_def
    by blast
qed

lemma transTerminationLessState1I:
assumes 
  "(x, y)  terminationLessState1 Vbl"
  "(y, z)  terminationLessState1 Vbl"
shows
  "(x, z)  terminationLessState1 Vbl"
using assms
using transTerminationLessState1[of "Vbl"]
unfolding trans_def
by blast


lemma TerminationLessAfterExhaustiveUnitPropagate:
assumes
  "exhaustiveUnitPropagate_dom state"
  "InvariantUniq (getM state)"
  "InvariantConsistent (getM state)"
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)"
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)"
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)"
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)"
  "InvariantUniqQ (getQ state)"
  "InvariantVarsM (getM state) F0 Vbl"
  "InvariantVarsQ (getQ state) F0 Vbl"
  "InvariantVarsF (getF state) F0 Vbl"
  "finite Vbl"
  "getSATFlag state = UNDEF"
shows
"let state' = exhaustiveUnitPropagate state in
    state' = state  (state', state)  terminationLessState1 (vars F0  Vbl)"
using assms
proof (induct state rule: exhaustiveUnitPropagate_dom.induct)
  case (step state')
  note ih = this
  show ?case
  proof (cases "(getConflictFlag state')  (getQ state') = []")
    case True
    with exhaustiveUnitPropagate.simps[of "state'"]
    have "exhaustiveUnitPropagate state' = state'"
      by simp
    thus ?thesis
      using True
      by (simp add: Let_def)
  next
    case False
    let ?state'' = "applyUnitPropagate state'"

    have "exhaustiveUnitPropagate state' = exhaustiveUnitPropagate ?state''"
      using exhaustiveUnitPropagate.simps[of "state'"]
      using False
      by simp
    have "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state'') (getF ?state'')" and
      "InvariantWatchListsUniq (getWatchList ?state'')" and
      "InvariantWatchListsCharacterization (getWatchList ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
      "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')" and
      "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')"
      using ih
      using WatchInvariantsAfterAssertLiteral[of "state'" "hd (getQ state')" "False"]
      unfolding applyUnitPropagate_def
      by (auto simp add: Let_def)
    moreover
    have "InvariantWatchCharacterization (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') (getM ?state'')"
      using ih
      using InvariantWatchCharacterizationAfterApplyUnitPropagate[of "state'"]
      unfolding InvariantQCharacterization_def
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantQCharacterization (getConflictFlag ?state'') (getQ ?state'') (getF ?state'') (getM ?state'')"
      using ih
      using InvariantQCharacterizationAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantConflictFlagCharacterization (getConflictFlag ?state'') (getF ?state'') (getM ?state'')"
      using ih
      using InvariantConflictFlagCharacterizationAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantUniqQ (getQ ?state'')"
      using ih
      using InvariantUniqQAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantConsistent (getM ?state'')"
      using ih
      using InvariantConsistentAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantUniq (getM ?state'')"
      using ih
      using InvariantUniqAfterApplyUnitPropagate[of "state'"]
      using False
      by (simp add: Let_def)
    moreover
    have "InvariantVarsM (getM ?state'') F0 Vbl" "InvariantVarsQ (getQ ?state'') F0 Vbl"
      using ih
      using False
      using InvariantsVarsAfterApplyUnitPropagate[of "state'" "F0" "Vbl"]
      by (auto simp add: Let_def)
    moreover
    have "InvariantVarsF (getF ?state'') F0 Vbl"
      unfolding applyUnitPropagate_def
      using assertLiteralEffect[of "state'" "hd (getQ state')" "False"]
      using ih
      by (simp add: Let_def)
    moreover
    have "getSATFlag ?state'' = UNDEF"
      unfolding applyUnitPropagate_def
      using ‹InvariantWatchListsContainOnlyClausesFromF (getWatchList state') (getF state')
      using ‹InvariantWatchesEl (getF state') (getWatch1 state') (getWatch2 state')
      using ‹getSATFlag state' = UNDEF›
      using assertLiteralEffect[of "state'" "hd (getQ state')" "False"]
      by (simp add: Let_def)
    ultimately
    have *: "exhaustiveUnitPropagate state' = applyUnitPropagate state'  
            (exhaustiveUnitPropagate state', applyUnitPropagate state')  terminationLessState1 (vars F0  Vbl)"
      using ih
      using False
      using ‹exhaustiveUnitPropagate state' = exhaustiveUnitPropagate ?state''
      by (simp add: Let_def)
    moreover
    have "(?state'', state')  terminationLessState1 (vars F0  Vbl)"
      using applyUnitPropagateEffect[of "state'"]
      using lexLessAppend[of "[(hd (getQ state'), False)]" "getM state'"]
      using False
      using ‹InvariantUniq (getM state')
      using ‹InvariantConsistent (getM state')
      using ‹InvariantVarsM (getM state') F0 Vbl
      using ‹InvariantWatchesEl (getF state') (getWatch1 state') (getWatch2 state')
      using ‹InvariantWatchListsContainOnlyClausesFromF (getWatchList state') (getF state')
      using ‹InvariantQCharacterization (getConflictFlag state') (getQ state') (getF state') (getM state')
      using ‹InvariantUniq (getM ?state'')
      using ‹InvariantConsistent (getM ?state'')
      using ‹InvariantVarsM (getM ?state'') F0 Vbl
      using ‹getSATFlag state' = UNDEF›
      using ‹getSATFlag ?state'' = UNDEF›
      unfolding terminationLessState1_def
      unfolding lexLessState1_def
      unfolding lexLessRestricted_def
      unfolding InvariantUniq_def
      unfolding InvariantConsistent_def
      unfolding InvariantVarsM_def
      by (auto simp add: Let_def)
    ultimately
    show ?thesis
      using transTerminationLessState1I[of "exhaustiveUnitPropagate state'" "applyUnitPropagate state'" "vars F0  Vbl" "state'"]
      by (auto simp add: Let_def)
  qed
qed


lemma InvariantsAfterSolveLoopBody:
assumes
  "getSATFlag state = UNDEF"
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)" and 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)" and
  "InvariantUniqQ (getQ state)" and
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)" and
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)" and
  "InvariantNoDecisionsWhenConflict (getF state) (getM state) (currentLevel (getM state))" and
  "InvariantNoDecisionsWhenUnit (getF state) (getM state) (currentLevel (getM state))" and
  "InvariantGetReasonIsReason (getReason state) (getF state) (getM state) (set (getQ state))" and
  "InvariantEquivalentZL (getF state) (getM state) F0'" and
  "InvariantConflictClauseCharacterization (getConflictFlag state) (getConflictClause state) (getF state) (getM state)" and
  "finite Vbl"
  "vars F0'  vars F0"
  "vars F0  Vbl"
  "InvariantVarsM (getM state) F0 Vbl"
  "InvariantVarsQ (getQ state) F0 Vbl"
  "InvariantVarsF (getF state) F0 Vbl"
shows
  "let state' = solve_loop_body state Vbl in
    (InvariantConsistent (getM state')  
     InvariantUniq (getM state')  
     InvariantWatchesEl (getF state') (getWatch1 state') (getWatch2 state')  
     InvariantWatchesDiffer (getF state') (getWatch1 state') (getWatch2 state')  
     InvariantWatchCharacterization (getF state') (getWatch1 state') (getWatch2 state') (getM state')  
     InvariantWatchListsContainOnlyClausesFromF (getWatchList state') (getF state')  
     InvariantWatchListsUniq (getWatchList state')  
     InvariantWatchListsCharacterization (getWatchList state') (getWatch1 state') (getWatch2 state')  
     InvariantQCharacterization (getConflictFlag state') (getQ state') (getF state') (getM state')  
     InvariantConflictFlagCharacterization (getConflictFlag state') (getF state') (getM state')  
     InvariantConflictClauseCharacterization (getConflictFlag state') (getConflictClause state') (getF state') (getM state')  
     InvariantUniqQ (getQ state'))  
    (InvariantNoDecisionsWhenConflict (getF state') (getM state') (currentLevel (getM state'))  
     InvariantNoDecisionsWhenUnit (getF state') (getM state') (currentLevel (getM state'))) 
     InvariantEquivalentZL (getF state') (getM state') F0'   
     InvariantGetReasonIsReason (getReason state') (getF state') (getM state') (set (getQ state'))  
     InvariantVarsM (getM state') F0 Vbl  
     InvariantVarsQ (getQ state') F0 Vbl  
     InvariantVarsF (getF state') F0 Vbl  
     (state', state)  terminationLessState1 (vars F0  Vbl)  
    ((getSATFlag state' = FALSE  ¬ satisfiable F0')  
     (getSATFlag state' = TRUE   satisfiable F0'))" 
     (is "let state' = solve_loop_body state Vbl in ?inv' state'  ?inv'' state'  _ ")
proof-
  let ?state_up = "exhaustiveUnitPropagate state"

  have "exhaustiveUnitPropagate_dom state"
    using exhaustiveUnitPropagateTermination[of "state" "F0" "Vbl"]
    using assms
    by simp

  have "?inv' ?state_up"
    using assms
    using ‹exhaustiveUnitPropagate_dom state
    using InvariantsAfterExhaustiveUnitPropagate[of "state"]
    using InvariantConflictClauseCharacterizationAfterExhaustivePropagate[of "state"]
    by (simp add: Let_def)
  have "?inv'' ?state_up"
    using assms
    using ‹exhaustiveUnitPropagate_dom state
    using InvariantsNoDecisionsWhenConflictNorUnitAfterExhaustivePropagate[of "state"]
    by (simp add: Let_def)
  have "InvariantEquivalentZL (getF ?state_up) (getM ?state_up) F0'"
    using assms
    using ‹exhaustiveUnitPropagate_dom state
    using InvariantEquivalentZLAfterExhaustiveUnitPropagate[of "state"]
    by (simp add: Let_def)
  have "InvariantGetReasonIsReason (getReason ?state_up) (getF ?state_up) (getM ?state_up) (set (getQ ?state_up))"
    using assms
    using ‹exhaustiveUnitPropagate_dom state
    using InvariantGetReasonIsReasonAfterExhaustiveUnitPropagate[of "state"]
    by (simp add: Let_def)
  have "getSATFlag ?state_up = getSATFlag state"
    using exhaustiveUnitPropagatePreservedVariables[of "state"]
    using assms
    using ‹exhaustiveUnitPropagate_dom state
    by (simp add: Let_def)
  have "getConflictFlag ?state_up  getQ ?state_up = []"
    using conflictFlagOrQEmptyAfterExhaustiveUnitPropagate[of "state"]
    using ‹exhaustiveUnitPropagate_dom state
    by (simp add: Let_def)
  have "InvariantVarsM (getM ?state_up) F0 Vbl" 
       "InvariantVarsQ (getQ ?state_up) F0 Vbl"
       "InvariantVarsF (getF ?state_up) F0 Vbl"
    using assms
    using ‹exhaustiveUnitPropagate_dom state
    using InvariantsAfterExhaustiveUnitPropagate[of "state" "F0" "Vbl"]
    by (auto simp add: Let_def)

  have "?state_up = state  (?state_up, state)  terminationLessState1 (vars F0  Vbl)"
    using assms
    using TerminationLessAfterExhaustiveUnitPropagate[of "state"]
    using ‹exhaustiveUnitPropagate_dom state
    by (simp add: Let_def)
  
  show ?thesis
  proof(cases "getConflictFlag ?state_up")
    case True
    show ?thesis
    proof (cases "currentLevel (getM ?state_up) = 0")
      case True
      hence "prefixToLevel 0 (getM ?state_up) = (getM ?state_up)"
        using currentLevelZeroTrailEqualsItsPrefixToLevelZero[of "getM ?state_up"]
        by simp
      moreover
      have "formulaFalse (getF ?state_up) (elements (getM ?state_up))"
        using ‹getConflictFlag ?state_up
        using ?inv' ?state_up
        unfolding InvariantConflictFlagCharacterization_def
        by simp
      ultimately
      have "¬ satisfiable F0'"
        using ‹InvariantEquivalentZL (getF ?state_up) (getM ?state_up) F0'
        unfolding InvariantEquivalentZL_def
        using soundnessForUNSAT[of "getF ?state_up" "elements (getM ?state_up)" "F0'"]
        by simp
      moreover
      let ?state' = "?state_up  getSATFlag := FALSE "
      have "(?state', state)  terminationLessState1 (vars F0  Vbl)"
        unfolding terminationLessState1_def
        unfolding satFlagLessState_def
        using ‹getSATFlag state = UNDEF›
        by simp
      ultimately
      show ?thesis
        using ?inv' ?state_up
        using ?inv'' ?state_up
        using ‹InvariantEquivalentZL (getF ?state_up) (getM ?state_up) F0'
        using ‹InvariantGetReasonIsReason (getReason ?state_up) (getF ?state_up)  (getM ?state_up) (set (getQ ?state_up))
        using ‹InvariantVarsM (getM ?state_up) F0 Vbl
        using ‹InvariantVarsQ (getQ ?state_up) F0 Vbl
        using ‹InvariantVarsF (getF ?state_up) F0 Vbl
        using ‹getConflictFlag ?state_up
        using ‹currentLevel (getM ?state_up) = 0
        unfolding solve_loop_body_def
        by (simp add: Let_def)
    next
      case False
      show ?thesis
      proof-
          (* APPLY CONFICT *)
        let ?state_c = "applyConflict ?state_up"

        have "?inv' ?state_c" 
          "?inv'' ?state_c"
          "getConflictFlag ?state_c"
          "InvariantEquivalentZL (getF ?state_c) (getM ?state_c) F0'"
          "currentLevel (getM ?state_c) > 0"
          using ?inv' ?state_up ?inv'' ?state_up
          using ‹getConflictFlag ?state_up
          using ‹InvariantEquivalentZL (getF ?state_up) (getM ?state_up) F0'
          using ‹currentLevel (getM ?state_up)  0
          unfolding applyConflict_def
          unfolding setConflictAnalysisClause_def
          by (auto simp add: Let_def findLastAssertedLiteral_def countCurrentLevelLiterals_def)

        have "InvariantCFalse (getConflictFlag ?state_c) (getM ?state_c) (getC ?state_c)"
             "InvariantCEntailed (getConflictFlag ?state_c) F0' (getC ?state_c)"
             "InvariantClCharacterization (getCl ?state_c) (getC ?state_c) (getM ?state_c)"
             "InvariantCnCharacterization (getCn ?state_c) (getC ?state_c) (getM ?state_c)"
             "InvariantClCurrentLevel (getCl ?state_c) (getM ?state_c)"
             "InvariantUniqC (getC ?state_c)"
          using ‹getConflictFlag ?state_up
          using ‹currentLevel (getM ?state_up)  0
          using ?inv' ?state_up
          using ?inv'' ?state_up
          using ‹InvariantEquivalentZL (getF ?state_up) (getM ?state_up) F0'
          using InvariantsClAfterApplyConflict[of "?state_up"]
          by (auto simp only: Let_def)

        have "getSATFlag ?state_c = getSATFlag state"
          using ‹getSATFlag ?state_up = getSATFlag state
          unfolding applyConflict_def
          unfolding setConflictAnalysisClause_def
          by (simp add: Let_def findLastAssertedLiteral_def countCurrentLevelLiterals_def)

        have "getReason ?state_c = getReason ?state_up"
          "getF ?state_c = getF ?state_up"
          "getM ?state_c = getM ?state_up"
          "getQ ?state_c = getQ ?state_up"
          unfolding applyConflict_def
          unfolding setConflictAnalysisClause_def
          by (auto simp add: Let_def findLastAssertedLiteral_def countCurrentLevelLiterals_def)
        hence "InvariantGetReasonIsReason (getReason ?state_c) (getF ?state_c) (getM ?state_c) (set (getQ ?state_c))"
          "InvariantVarsM (getM ?state_c) F0 Vbl" 
          "InvariantVarsQ (getQ ?state_c) F0 Vbl"
          "InvariantVarsF (getF ?state_c) F0 Vbl"         
          using ‹InvariantGetReasonIsReason (getReason ?state_up) (getF ?state_up) (getM ?state_up) (set (getQ ?state_up))
          using ‹InvariantVarsM (getM ?state_up) F0 Vbl
          using ‹InvariantVarsQ (getQ ?state_up) F0 Vbl
          using ‹InvariantVarsF (getF ?state_up) F0 Vbl
          by auto


        have "getM ?state_c = getM state  (?state_c, state)  terminationLessState1 (vars F0  Vbl)"
          using ?state_up = state  (?state_up, state)  terminationLessState1 (vars F0  Vbl)
          using ‹getM ?state_c = getM ?state_up
          using ‹getSATFlag ?state_c = getSATFlag state
          using ‹InvariantUniq (getM state)
          using ‹InvariantConsistent (getM state)
          using ‹InvariantVarsM (getM state) F0 Vbl
          using ?inv' ?state_up
          using ‹InvariantVarsM (getM ?state_up) F0 Vbl
          using ‹getSATFlag ?state_up = getSATFlag state
          using ‹getSATFlag state = UNDEF›
          unfolding InvariantConsistent_def
          unfolding InvariantUniq_def
          unfolding InvariantVarsM_def
          unfolding terminationLessState1_def
          unfolding satFlagLessState_def
          unfolding lexLessState1_def
          unfolding lexLessRestricted_def
          by auto


          (*    APPLY EXPLAIN UIP    *)
          
        let ?state_euip = "applyExplainUIP ?state_c"
        let ?l' = "getCl ?state_euip"

        have "applyExplainUIP_dom ?state_c"
          using ApplyExplainUIPTermination[of "?state_c" "F0'"]
          using ‹getConflictFlag ?state_c
          using ‹InvariantEquivalentZL (getF ?state_c) (getM ?state_c) F0'
          using ‹currentLevel (getM ?state_c) > 0
          using ?inv' ?state_c
          using ‹InvariantCFalse (getConflictFlag ?state_c) (getM ?state_c) (getC ?state_c)
          using ‹InvariantCEntailed (getConflictFlag ?state_c) F0' (getC ?state_c)
          using ‹InvariantClCharacterization (getCl ?state_c) (getC ?state_c) (getM ?state_c)
          using ‹InvariantCnCharacterization (getCn ?state_c) (getC ?state_c) (getM ?state_c)
          using ‹InvariantClCurrentLevel (getCl ?state_c) (getM ?state_c)
          using ‹InvariantGetReasonIsReason (getReason ?state_c) (getF ?state_c) (getM ?state_c) (set (getQ ?state_c))
          by simp
        
        
        have "?inv' ?state_euip" "?inv'' ?state_euip"
          using ?inv' ?state_c ?inv'' ?state_c
          using ‹applyExplainUIP_dom ?state_c
          using ApplyExplainUIPPreservedVariables[of "?state_c"]
          by (auto simp add: Let_def)

        have "InvariantCFalse (getConflictFlag ?state_euip) (getM ?state_euip) (getC ?state_euip)"
          "InvariantCEntailed (getConflictFlag ?state_euip) F0' (getC ?state_euip)"
          "InvariantClCharacterization (getCl ?state_euip) (getC ?state_euip) (getM ?state_euip)"
          "InvariantCnCharacterization (getCn ?state_euip) (getC ?state_euip) (getM ?state_euip)"
          "InvariantClCurrentLevel (getCl ?state_euip) (getM ?state_euip)"
          "InvariantUniqC (getC ?state_euip)"
          using ?inv' ?state_c
          using ‹InvariantCFalse (getConflictFlag ?state_c) (getM ?state_c) (getC ?state_c)
          using ‹InvariantCEntailed (getConflictFlag ?state_c) F0' (getC ?state_c)
          using ‹InvariantClCharacterization (getCl ?state_c) (getC ?state_c) (getM ?state_c)
          using ‹InvariantCnCharacterization (getCn ?state_c) (getC ?state_c) (getM ?state_c)
          using ‹InvariantClCurrentLevel (getCl ?state_c) (getM ?state_c)
          using ‹InvariantEquivalentZL (getF ?state_c) (getM ?state_c) F0'
          using ‹InvariantUniqC (getC ?state_c)
          using ‹getConflictFlag ?state_c
          using ‹currentLevel (getM ?state_c) > 0
          using ‹InvariantGetReasonIsReason (getReason ?state_c) (getF ?state_c) (getM ?state_c) (set (getQ ?state_c))
          using ‹applyExplainUIP_dom ?state_c
          using InvariantsClAfterExplainUIP[of "?state_c" "F0'"]
          by (auto simp only: Let_def)

        have "InvariantEquivalentZL (getF ?state_euip) (getM ?state_euip) F0'"
          using ‹InvariantEquivalentZL (getF ?state_c) (getM ?state_c) F0'
          using ‹applyExplainUIP_dom ?state_c
          using ApplyExplainUIPPreservedVariables[of "?state_c"]
          by (simp only: Let_def)

        have "InvariantGetReasonIsReason (getReason ?state_euip) (getF ?state_euip) (getM ?state_euip) (set (getQ ?state_euip))"
          using ‹InvariantGetReasonIsReason (getReason ?state_c) (getF ?state_c) (getM ?state_c) (set (getQ ?state_c))
          using ‹applyExplainUIP_dom ?state_c
          using ApplyExplainUIPPreservedVariables[of "?state_c"]
          by (simp only: Let_def)

        have "getConflictFlag ?state_euip"
          using ‹getConflictFlag ?state_c
          using ‹applyExplainUIP_dom ?state_c
          using ApplyExplainUIPPreservedVariables[of "?state_c"]
          by (simp add: Let_def)

        hence "getSATFlag ?state_euip = getSATFlag state"
          using ‹getSATFlag ?state_c = getSATFlag state
          using ‹applyExplainUIP_dom ?state_c
          using ApplyExplainUIPPreservedVariables[of "?state_c"]
          by (simp add: Let_def)

        have "isUIP (opposite (getCl ?state_euip)) (getC ?state_euip) (getM ?state_euip)"
          using ‹applyExplainUIP_dom ?state_c
          using ?inv' ?state_c
          using ‹InvariantCFalse (getConflictFlag ?state_c) (getM ?state_c) (getC ?state_c)
          using ‹InvariantCEntailed (getConflictFlag ?state_c) F0' (getC ?state_c)
          using ‹InvariantClCharacterization (getCl ?state_c) (getC ?state_c) (getM ?state_c)
          using ‹InvariantCnCharacterization (getCn ?state_c) (getC ?state_c) (getM ?state_c)
          using ‹InvariantClCurrentLevel (getCl ?state_c) (getM ?state_c)
          using ‹InvariantGetReasonIsReason (getReason ?state_c) (getF ?state_c) (getM ?state_c) (set (getQ ?state_c))
          using ‹InvariantEquivalentZL (getF ?state_c) (getM ?state_c) F0'
          using ‹getConflictFlag ?state_c
          using ‹currentLevel (getM ?state_c) > 0
          using isUIPApplyExplainUIP[of "?state_c"]
          by (simp add: Let_def)

        have "currentLevel (getM ?state_euip) > 0"
          using ‹applyExplainUIP_dom ?state_c
          using ApplyExplainUIPPreservedVariables[of "?state_c"]
          using ‹currentLevel (getM ?state_c) > 0
          by (simp add: Let_def)

        have "InvariantVarsM (getM ?state_euip) F0 Vbl" 
             "InvariantVarsQ (getQ ?state_euip) F0 Vbl"
             "InvariantVarsF (getF ?state_euip) F0 Vbl"
          using ‹InvariantVarsM (getM ?state_c) F0 Vbl
          using ‹InvariantVarsQ (getQ ?state_c) F0 Vbl
          using ‹InvariantVarsF (getF ?state_c) F0 Vbl
          using ‹applyExplainUIP_dom ?state_c
          using ApplyExplainUIPPreservedVariables[of "?state_c"]
          by (auto simp add: Let_def)

        have "getM ?state_euip = getM state  (?state_euip, state)  terminationLessState1 (vars F0  Vbl)"
          using ‹getM ?state_c = getM state  (?state_c, state)  terminationLessState1 (vars F0  Vbl)
          using ‹applyExplainUIP_dom ?state_c
          using ApplyExplainUIPPreservedVariables[of "?state_c"]
          unfolding terminationLessState1_def
          unfolding satFlagLessState_def
          unfolding lexLessState1_def
          unfolding lexLessRestricted_def
          by (simp add: Let_def)

            (*    APPLY LEARN    *)
        let ?state_l = "applyLearn ?state_euip"
        let ?l'' = "getCl ?state_l"

        have $: "getM ?state_l = getM ?state_euip  
                 getQ ?state_l = getQ ?state_euip  
                 getC ?state_l = getC ?state_euip  
                 getCl ?state_l = getCl ?state_euip 
                 getConflictFlag ?state_l = getConflictFlag ?state_euip  
                 getConflictClause ?state_l = getConflictClause ?state_euip  
                 getF ?state_l = (if getC ?state_euip = [opposite ?l'] then 
                                     getF ?state_euip 
                                  else 
                                     (getF ?state_euip @ [getC ?state_euip])
                                 )"
          using applyLearnPreservedVariables[of "?state_euip"]
          by (simp add: Let_def)

        have "?inv' ?state_l"
        proof-
          have "InvariantConflictFlagCharacterization (getConflictFlag ?state_l) (getF ?state_l) (getM ?state_l)"
            using ?inv' ?state_euip
            using ‹getConflictFlag ?state_euip
            using InvariantConflictFlagCharacterizationAfterApplyLearn[of "?state_euip"]
            by (simp add: Let_def)
          moreover
          hence "InvariantQCharacterization (getConflictFlag ?state_l) (getQ ?state_l) (getF ?state_l) (getM ?state_l)"
            using ?inv' ?state_euip
            using ‹getConflictFlag ?state_euip
            using InvariantQCharacterizationAfterApplyLearn[of "?state_euip"]
            by (simp add: Let_def)
          moreover
          have "InvariantUniqQ (getQ ?state_l)"
            using ?inv' ?state_euip
            using InvariantUniqQAfterApplyLearn[of "?state_euip"]
            by (simp add: Let_def)
          moreover
          have "InvariantConflictClauseCharacterization (getConflictFlag ?state_l) (getConflictClause ?state_l) (getF ?state_l) (getM ?state_l)"
            using ?inv' ?state_euip
            using ‹getConflictFlag ?state_euip
            using InvariantConflictClauseCharacterizationAfterApplyLearn[of "?state_euip"]
            by (simp only: Let_def)
          ultimately
          show ?thesis
            using ?inv' ?state_euip
            using ‹getConflictFlag ?state_euip
            using ‹InvariantUniqC (getC ?state_euip)
            using ‹InvariantCFalse (getConflictFlag ?state_euip) (getM ?state_euip) (getC ?state_euip)
            using ‹InvariantClCharacterization (getCl ?state_euip) (getC ?state_euip) (getM ?state_euip)
            using ‹isUIP (opposite (getCl ?state_euip)) (getC ?state_euip) (getM ?state_euip)
            using WatchInvariantsAfterApplyLearn[of "?state_euip"]
            using $
            by (auto simp only: Let_def)
        qed

        have "InvariantNoDecisionsWhenConflict (getF ?state_euip) (getM ?state_l) (currentLevel (getM ?state_l))"
             "InvariantNoDecisionsWhenUnit (getF ?state_euip) (getM ?state_l) (currentLevel (getM ?state_l))"
             "InvariantNoDecisionsWhenConflict [getC ?state_euip] (getM ?state_l) (getBackjumpLevel ?state_l)"
             "InvariantNoDecisionsWhenUnit [getC ?state_euip] (getM ?state_l) (getBackjumpLevel ?state_l)"
          using InvariantNoDecisionsWhenConflictNorUnitAfterApplyLearn[of "?state_euip"]
          using ?inv' ?state_euip
          using ?inv'' ?state_euip
          using ‹getConflictFlag ?state_euip
          using ‹InvariantUniqC (getC ?state_euip)
          using ‹InvariantCFalse (getConflictFlag ?state_euip) (getM ?state_euip) (getC ?state_euip)
          using ‹InvariantClCharacterization (getCl ?state_euip) (getC ?state_euip) (getM ?state_euip)
          using ‹InvariantClCurrentLevel (getCl ?state_euip) (getM ?state_euip)
          using ‹isUIP (opposite (getCl ?state_euip)) (getC ?state_euip) (getM ?state_euip)
          using ‹currentLevel (getM ?state_euip) > 0
          by (auto simp only: Let_def)
        

        have "isUIP (opposite (getCl ?state_l)) (getC ?state_l) (getM ?state_l)"
          using ‹isUIP (opposite (getCl ?state_euip)) (getC ?state_euip) (getM ?state_euip)
          using $
          by simp

        have "InvariantClCurrentLevel (getCl ?state_l) (getM ?state_l)"
          using ‹InvariantClCurrentLevel (getCl ?state_euip) (getM ?state_euip)
          using $
          by simp

        have "InvariantCEntailed (getConflictFlag ?state_l) F0' (getC ?state_l)"
          using ‹InvariantCEntailed (getConflictFlag ?state_euip) F0' (getC ?state_euip)
          using $
          unfolding InvariantCEntailed_def
          by simp

        have "InvariantCFalse (getConflictFlag ?state_l) (getM ?state_l) (getC ?state_l)"
          using ‹InvariantCFalse (getConflictFlag ?state_euip) (getM ?state_euip) (getC ?state_euip)
          using $
          by simp

        have "InvariantUniqC (getC ?state_l)"
          using ‹InvariantUniqC (getC ?state_euip)
          using $
          by simp

        have "InvariantClCharacterization (getCl ?state_l) (getC ?state_l) (getM ?state_l)"
          using ‹InvariantClCharacterization (getCl ?state_euip) (getC ?state_euip) (getM ?state_euip)
          unfolding applyLearn_def
          unfolding setWatch1_def
          unfolding setWatch2_def
          by (auto simp add:Let_def)

        have "InvariantCllCharacterization (getCl ?state_l) (getCll ?state_l) (getC ?state_l) (getM ?state_l)"
          using ‹InvariantClCharacterization (getCl ?state_euip) (getC ?state_euip) (getM ?state_euip)
            ‹InvariantUniqC (getC ?state_euip)
            ‹InvariantCFalse (getConflictFlag ?state_euip) (getM ?state_euip) (getC ?state_euip)
            ‹getConflictFlag ?state_euip
            ?inv' ?state_euip
          using InvariantCllCharacterizationAfterApplyLearn[of "?state_euip"]
          by (simp add: Let_def)

        have "InvariantEquivalentZL (getF ?state_l) (getM ?state_l) F0'"
          using ‹InvariantEquivalentZL (getF ?state_euip) (getM ?state_euip) F0'
          using ‹getConflictFlag ?state_euip
          using InvariantEquivalentZLAfterApplyLearn[of "?state_euip" "F0'"]
          using ‹InvariantCEntailed (getConflictFlag ?state_euip) F0' (getC ?state_euip)
          by (simp add: Let_def)

        have "InvariantGetReasonIsReason (getReason ?state_l) (getF ?state_l) (getM ?state_l) (set (getQ ?state_l))"
          using ‹InvariantGetReasonIsReason (getReason ?state_euip) (getF ?state_euip) (getM ?state_euip) (set (getQ ?state_euip))
          using InvariantGetReasonIsReasonAfterApplyLearn[of "?state_euip"]
          by (simp only: Let_def)

        have "InvariantVarsM (getM ?state_l) F0 Vbl" 
          "InvariantVarsQ (getQ ?state_l) F0 Vbl"
          "InvariantVarsF (getF ?state_l) F0 Vbl"
          using ‹InvariantVarsM (getM ?state_euip) F0 Vbl
          using ‹InvariantVarsQ (getQ ?state_euip) F0 Vbl
          using ‹InvariantVarsF (getF ?state_euip) F0 Vbl
          using $
          using ‹InvariantCFalse (getConflictFlag ?state_euip) (getM ?state_euip) (getC ?state_euip) 
          using ‹getConflictFlag ?state_euip
          using InvariantVarsFAfterApplyLearn[of "?state_euip" "F0" "Vbl"]
          by auto

        have "getConflictFlag ?state_l"
          using ‹getConflictFlag ?state_euip
          using $
          by simp

        have "getSATFlag ?state_l = getSATFlag state"
          using ‹getSATFlag ?state_euip = getSATFlag state
          unfolding applyLearn_def
          unfolding setWatch2_def
          unfolding setWatch1_def
          by (simp add: Let_def)


        have "currentLevel (getM ?state_l) > 0"
          using ‹currentLevel (getM ?state_euip) > 0
          using $
          by simp

        have "getM ?state_l = getM state  (?state_l, state)  terminationLessState1 (vars F0  Vbl)"
        proof (cases "getM ?state_euip = getM state")
          case True
          thus ?thesis
            using $
            by simp
        next
          case False
          with ‹getM ?state_euip = getM state  (?state_euip, state)  terminationLessState1 (vars F0  Vbl)
          have "(?state_euip, state)  terminationLessState1 (vars F0  Vbl)"
            by simp
          hence "(?state_l, state)  terminationLessState1 (vars F0  Vbl)"
            using $
            using ‹getSATFlag ?state_l = getSATFlag state
            using ‹getSATFlag ?state_euip = getSATFlag state
            unfolding terminationLessState1_def
            unfolding satFlagLessState_def
            unfolding lexLessState1_def
            unfolding lexLessRestricted_def
            by (simp add: Let_def)
          thus ?thesis
            by simp
        qed

      (*    APPLY BACKJUMP    *)
        let ?state_bj = "applyBackjump ?state_l"
        
        have "?inv' ?state_bj  
           InvariantVarsM (getM ?state_bj) F0 Vbl  
           InvariantVarsQ (getQ ?state_bj) F0 Vbl  
           InvariantVarsF (getF ?state_bj) F0 Vbl"
        proof (cases "getC ?state_l = [opposite ?l'']")
          case True
          thus ?thesis
            using WatchInvariantsAfterApplyBackjump[of "?state_l" "F0'"]
            using InvariantUniqAfterApplyBackjump[of "?state_l" "F0'"]
            using InvariantConsistentAfterApplyBackjump[of "?state_l" "F0'"]
            using invariantQCharacterizationAfterApplyBackjump_1[of "?state_l" "F0'"]
            using InvariantConflictFlagCharacterizationAfterApplyBackjump_1[of "?state_l" "F0'"]
            using InvariantUniqQAfterApplyBackjump[of "?state_l"]
            using InvariantConflictClauseCharacterizationAfterApplyBackjump[of "?state_l"]
            using InvariantsVarsAfterApplyBackjump[of "?state_l" "F0'" "F0" "Vbl"]
            using ?inv' ?state_l
            using ‹getConflictFlag ?state_l
            using ‹InvariantClCurrentLevel (getCl ?state_l) (getM ?state_l)
            using ‹InvariantUniqC (getC ?state_l)
            using ‹InvariantCFalse (getConflictFlag ?state_l) (getM ?state_l) (getC ?state_l)
            using ‹InvariantCEntailed (getConflictFlag ?state_l) F0' (getC ?state_l)
            using ‹InvariantClCharacterization (getCl ?state_l) (getC ?state_l) (getM ?state_l)
            using ‹InvariantCllCharacterization (getCl ?state_l) (getCll ?state_l) (getC ?state_l) (getM ?state_l)
            using ‹isUIP (opposite (getCl ?state_l)) (getC ?state_l) (getM ?state_l)
            using ‹currentLevel (getM ?state_l) > 0
            using ‹InvariantNoDecisionsWhenConflict (getF ?state_euip) (getM ?state_l) (currentLevel (getM ?state_l))
            using ‹InvariantNoDecisionsWhenUnit (getF ?state_euip) (getM ?state_l) (currentLevel (getM ?state_l))
            using ‹InvariantEquivalentZL (getF ?state_l) (getM ?state_l) F0'
            using ‹InvariantVarsM (getM ?state_l) F0 Vbl
            using ‹InvariantVarsQ (getQ ?state_l) F0 Vbl
            using ‹InvariantVarsF (getF ?state_l) F0 Vbl
            using ‹vars F0'  vars F0
            using $
            by (simp add: Let_def)
        next
          case False
          thus ?thesis
            using WatchInvariantsAfterApplyBackjump[of "?state_l" "F0'"]
            using InvariantUniqAfterApplyBackjump[of "?state_l" "F0'"]
            using InvariantConsistentAfterApplyBackjump[of "?state_l" "F0'"]
            using invariantQCharacterizationAfterApplyBackjump_2[of "?state_l" "F0'"]
            using InvariantConflictFlagCharacterizationAfterApplyBackjump_2[of "?state_l" "F0'"]
            using InvariantUniqQAfterApplyBackjump[of "?state_l"]
            using InvariantConflictClauseCharacterizationAfterApplyBackjump[of "?state_l"]
            using InvariantsVarsAfterApplyBackjump[of "?state_l" "F0'" "F0" "Vbl"]
            using ?inv' ?state_l
            using ‹getConflictFlag ?state_l
            using ‹InvariantClCurrentLevel (getCl ?state_l) (getM ?state_l)
            using ‹InvariantUniqC (getC ?state_l)
            using ‹InvariantCFalse (getConflictFlag ?state_l) (getM ?state_l) (getC ?state_l)
            using ‹InvariantCEntailed (getConflictFlag ?state_l) F0' (getC ?state_l)
            using ‹InvariantClCharacterization (getCl ?state_l) (getC ?state_l) (getM ?state_l)
            using ‹InvariantCllCharacterization (getCl ?state_l) (getCll ?state_l) (getC ?state_l) (getM ?state_l)
            using ‹isUIP (opposite (getCl ?state_l)) (getC ?state_l) (getM ?state_l)
            using ‹currentLevel (getM ?state_l) > 0
            using ‹InvariantNoDecisionsWhenConflict (getF ?state_euip) (getM ?state_l) (currentLevel (getM ?state_l))
            using ‹InvariantNoDecisionsWhenUnit (getF ?state_euip) (getM ?state_l) (currentLevel (getM ?state_l))
            using ‹InvariantNoDecisionsWhenConflict [getC ?state_euip] (getM ?state_l) (getBackjumpLevel ?state_l)
            using ‹InvariantNoDecisionsWhenUnit [getC ?state_euip] (getM ?state_l) (getBackjumpLevel ?state_l)
            using $
            using ‹InvariantEquivalentZL (getF ?state_l) (getM ?state_l) F0'
            using ‹InvariantVarsM (getM ?state_l) F0 Vbl
            using ‹InvariantVarsQ (getQ ?state_l) F0 Vbl
            using ‹InvariantVarsF (getF ?state_l) F0 Vbl
            using ‹vars F0'  vars F0
            by (simp add: Let_def)
        qed

        have "?inv'' ?state_bj"
        proof (cases "getC ?state_l = [opposite ?l'']")
          case True
          thus ?thesis
            using InvariantsNoDecisionsWhenConflictNorUnitAfterApplyBackjump_1[of "?state_l" "F0'"]
            using ?inv' ?state_l
            using ‹getConflictFlag ?state_l
            using ‹InvariantClCurrentLevel (getCl ?state_l) (getM ?state_l)
            using ‹InvariantUniqC (getC ?state_l)
            using ‹InvariantCFalse (getConflictFlag ?state_l) (getM ?state_l) (getC ?state_l)
            using ‹InvariantCEntailed (getConflictFlag ?state_l) F0' (getC ?state_l)
            using ‹InvariantClCharacterization (getCl ?state_l) (getC ?state_l) (getM ?state_l)
            using ‹InvariantCllCharacterization (getCl ?state_l) (getCll ?state_l) (getC ?state_l) (getM ?state_l)
            using ‹isUIP (opposite (getCl ?state_l)) (getC ?state_l) (getM ?state_l)
            using ‹currentLevel (getM ?state_l) > 0
            using ‹InvariantNoDecisionsWhenConflict (getF ?state_euip) (getM ?state_l) (currentLevel (getM ?state_l))
            using ‹InvariantNoDecisionsWhenUnit (getF ?state_euip) (getM ?state_l) (currentLevel (getM ?state_l))
            using $
            by (simp add: Let_def)
        next
          case False
          thus ?thesis
            using InvariantsNoDecisionsWhenConflictNorUnitAfterApplyBackjump_2[of "?state_l"]
            using ?inv' ?state_l
            using ‹getConflictFlag ?state_l
            using ‹InvariantClCurrentLevel (getCl ?state_l) (getM ?state_l)
            using ‹InvariantCFalse (getConflictFlag ?state_l) (getM ?state_l) (getC ?state_l)
            using ‹InvariantUniqC (getC ?state_l)
            using ‹InvariantCEntailed (getConflictFlag ?state_l) F0' (getC ?state_l)
            using ‹InvariantClCharacterization (getCl ?state_l) (getC ?state_l) (getM ?state_l)
            using ‹InvariantCllCharacterization (getCl ?state_l) (getCll ?state_l) (getC ?state_l) (getM ?state_l)
            using ‹isUIP (opposite (getCl ?state_l)) (getC ?state_l) (getM ?state_l)
            using ‹currentLevel (getM ?state_l) > 0
            using ‹InvariantNoDecisionsWhenConflict (getF ?state_euip) (getM ?state_l) (currentLevel (getM ?state_l))
            using ‹InvariantNoDecisionsWhenUnit (getF ?state_euip) (getM ?state_l) (currentLevel (getM ?state_l))
            using ‹InvariantNoDecisionsWhenConflict [getC ?state_euip] (getM ?state_l) (getBackjumpLevel ?state_l)
            using ‹InvariantNoDecisionsWhenUnit [getC ?state_euip] (getM ?state_l) (getBackjumpLevel ?state_l)
            using $
            by (simp add: Let_def)
        qed

        

        have "getBackjumpLevel ?state_l > 0  (getF ?state_l)  []  (last (getF ?state_l) = (getC ?state_l))"
        proof (cases "getC ?state_l = [opposite ?l'']")
          case True
          thus ?thesis
            unfolding getBackjumpLevel_def
            by simp
        next
          case False
          thus ?thesis
            using $
            by simp
        qed
        hence "InvariantGetReasonIsReason (getReason ?state_bj) (getF ?state_bj) (getM ?state_bj) (set (getQ ?state_bj))"
          using ‹InvariantGetReasonIsReason (getReason ?state_l) (getF ?state_l) (getM ?state_l) (set (getQ ?state_l))
          using ?inv' ?state_l
          using ‹getConflictFlag ?state_l
          using ‹isUIP (opposite (getCl ?state_l)) (getC ?state_l) (getM ?state_l)
          using ‹InvariantClCurrentLevel (getCl ?state_l) (getM ?state_l)
          using ‹InvariantCEntailed (getConflictFlag ?state_l) F0' (getC ?state_l)
          using ‹InvariantCFalse (getConflictFlag ?state_l) (getM ?state_l) (getC ?state_l)
          using ‹InvariantUniqC (getC ?state_l)
          using ‹InvariantClCharacterization (getCl ?state_l) (getC ?state_l) (getM ?state_l)
          using ‹InvariantCllCharacterization (getCl ?state_l) (getCll ?state_l) (getC ?state_l) (getM ?state_l)
          using ‹currentLevel (getM ?state_l) > 0
          using InvariantGetReasonIsReasonAfterApplyBackjump[of "?state_l" "F0'"]
          by (simp only: Let_def)

        have "InvariantEquivalentZL (getF ?state_bj) (getM ?state_bj) F0'"
          using ‹InvariantEquivalentZL (getF ?state_l) (getM ?state_l) F0'
          using ?inv' ?state_l
          using ‹getConflictFlag ?state_l
          using ‹isUIP (opposite (getCl ?state_l)) (getC ?state_l) (getM ?state_l)
          using ‹InvariantClCurrentLevel (getCl ?state_l) (getM ?state_l)
          using ‹InvariantUniqC (getC ?state_l)
          using ‹InvariantCEntailed (getConflictFlag ?state_l) F0' (getC ?state_l)
          using ‹InvariantCFalse (getConflictFlag ?state_l) (getM ?state_l) (getC ?state_l)
          using ‹InvariantClCharacterization (getCl ?state_l) (getC ?state_l) (getM ?state_l)
          using ‹InvariantCllCharacterization (getCl ?state_l) (getCll ?state_l) (getC ?state_l) (getM ?state_l)
          using InvariantEquivalentZLAfterApplyBackjump[of "?state_l" "F0'"]
          using ‹currentLevel (getM ?state_l) > 0
          by (simp only: Let_def)


        have "getSATFlag ?state_bj = getSATFlag state"
          using ‹getSATFlag ?state_l = getSATFlag state
          using ?inv' ?state_l
          using applyBackjumpPreservedVariables[of "?state_l"]
          by (simp only: Let_def)

        let ?level = "getBackjumpLevel ?state_l"
        let ?prefix = "prefixToLevel ?level (getM ?state_l)"
        let ?l = "opposite (getCl ?state_l)"

        have "isMinimalBackjumpLevel (getBackjumpLevel ?state_l) (opposite (getCl ?state_l)) (getC ?state_l) (getM ?state_l)"
          using isMinimalBackjumpLevelGetBackjumpLevel[of "?state_l"]
          using ?inv' ?state_l
          using ‹InvariantClCurrentLevel (getCl ?state_l) (getM ?state_l)
          using ‹InvariantCEntailed (getConflictFlag ?state_l) F0' (getC ?state_l)
          using ‹InvariantCFalse (getConflictFlag ?state_l) (getM ?state_l) (getC ?state_l)
          using ‹InvariantUniqC (getC ?state_l)
          using ‹InvariantClCharacterization (getCl ?state_l) (getC ?state_l) (getM ?state_l)
          using ‹InvariantCllCharacterization (getCl ?state_l) (getCll ?state_l) (getC ?state_l) (getM ?state_l)
          using ‹isUIP (opposite (getCl ?state_l)) (getC ?state_l) (getM ?state_l)
          using ‹getConflictFlag ?state_l
          using ‹currentLevel (getM ?state_l) > 0
          by (simp add: Let_def)
        hence "getBackjumpLevel ?state_l < elementLevel (getCl ?state_l) (getM ?state_l)"
          unfolding isMinimalBackjumpLevel_def
          unfolding isBackjumpLevel_def
          by simp
        hence "getBackjumpLevel ?state_l < currentLevel (getM ?state_l)"
          using elementLevelLeqCurrentLevel[of "getCl ?state_l" "getM ?state_l"]
          by simp
        hence "(?state_bj, ?state_l)  terminationLessState1 (vars F0  Vbl)"
          using applyBackjumpEffect[of "?state_l" "F0'"]
          using ?inv' ?state_l
          using ‹getConflictFlag ?state_l
          using ‹isUIP (opposite (getCl ?state_l)) (getC ?state_l) (getM ?state_l)
          using ‹InvariantClCurrentLevel (getCl ?state_l) (getM ?state_l)
          using ‹InvariantCEntailed (getConflictFlag ?state_l) F0' (getC ?state_l)
          using ‹InvariantCFalse (getConflictFlag ?state_l) (getM ?state_l) (getC ?state_l)
          using ‹InvariantUniqC (getC ?state_l)
          using ‹InvariantClCharacterization (getCl ?state_l) (getC ?state_l) (getM ?state_l)
          using ‹InvariantCllCharacterization (getCl ?state_l) (getCll ?state_l) (getC ?state_l) (getM ?state_l)
          using ‹currentLevel (getM ?state_l) > 0
          using lexLessBackjump[of "?prefix" "?level" "getM ?state_l" "?l"]
          using ‹getSATFlag ?state_bj = getSATFlag state
          using ‹getSATFlag ?state_l = getSATFlag state
          using ‹getSATFlag state = UNDEF›
          using ?inv' ?state_l
          using ‹InvariantVarsM (getM ?state_l) F0 Vbl
          using ?inv' ?state_bj  InvariantVarsM (getM ?state_bj) F0 Vbl  
           InvariantVarsQ (getQ ?state_bj) F0 Vbl  
           InvariantVarsF (getF ?state_bj) F0 Vbl
          unfolding InvariantConsistent_def
          unfolding InvariantUniq_def
          unfolding InvariantVarsM_def
          unfolding terminationLessState1_def
          unfolding satFlagLessState_def
          unfolding lexLessState1_def
          unfolding lexLessRestricted_def
          by (simp add: Let_def)
        hence "(?state_bj, state)  terminationLessState1 (vars F0  Vbl)"
          using ‹getM ?state_l = getM state  (?state_l, state)  terminationLessState1 (vars F0  Vbl)
          using ‹getSATFlag state = UNDEF›
          using ‹getSATFlag ?state_bj = getSATFlag state
          using ‹getSATFlag ?state_l = getSATFlag state
          using transTerminationLessState1I[of "?state_bj" "?state_l" "vars F0  Vbl" "state"]
          unfolding terminationLessState1_def
          unfolding satFlagLessState_def
          unfolding lexLessState1_def
          unfolding lexLessRestricted_def
          by auto

        show ?thesis
          using ?inv' ?state_bj  InvariantVarsM (getM ?state_bj) F0 Vbl  
           InvariantVarsQ (getQ ?state_bj) F0 Vbl  
           InvariantVarsF (getF ?state_bj) F0 Vbl
          using ?inv'' ?state_bj
          using ‹InvariantEquivalentZL (getF ?state_bj) (getM ?state_bj) F0'
          using ‹InvariantGetReasonIsReason (getReason ?state_bj) (getF ?state_bj) (getM ?state_bj) (set (getQ ?state_bj))
          using ‹getSATFlag state = UNDEF›
          using ‹getSATFlag ?state_bj = getSATFlag state
          using ‹getConflictFlag ?state_up
          using ‹currentLevel (getM ?state_up)  0
          using (?state_bj, state)  terminationLessState1 (vars F0  Vbl)
          unfolding solve_loop_body_def
          by (auto simp add: Let_def)
      qed
    qed
  next
    case False
    show ?thesis
    proof (cases "vars (elements (getM ?state_up))  Vbl")
      case True
      hence "satisfiable F0'"
        using soundnessForSat[of "F0'" "Vbl" "getF ?state_up" "getM ?state_up"]
        using ‹InvariantEquivalentZL (getF ?state_up) (getM ?state_up) F0'
        using ?inv' ?state_up
        using ‹InvariantVarsF (getF ?state_up) F0 Vbl
        using ¬ getConflictFlag ?state_up
        using ‹vars F0  Vbl
        using ‹vars F0'  vars F0
        using True
        unfolding InvariantConflictFlagCharacterization_def
        unfolding satisfiable_def
        unfolding InvariantVarsF_def
        by blast
      moreover
      let ?state' = "?state_up  getSATFlag := TRUE "
      have "(?state', state)  terminationLessState1 (vars F0  Vbl)"
        using ‹getSATFlag state = UNDEF›
        unfolding terminationLessState1_def
        unfolding satFlagLessState_def
        by simp
      ultimately
      show ?thesis
        using ‹vars (elements (getM ?state_up))  Vbl
        using ?inv' ?state_up
        using ?inv'' ?state_up
        using ‹InvariantEquivalentZL (getF ?state_up) (getM ?state_up) F0'
        using ‹InvariantGetReasonIsReason (getReason ?state_up) (getF ?state_up)  (getM ?state_up) (set (getQ ?state_up))
        using ‹InvariantVarsM (getM ?state_up) F0 Vbl
        using ‹InvariantVarsQ (getQ ?state_up) F0 Vbl
        using ‹InvariantVarsF (getF ?state_up) F0 Vbl
        using ¬ getConflictFlag ?state_up
        unfolding solve_loop_body_def
        by (simp add: Let_def)
    next
      case False
      let ?literal = "selectLiteral ?state_up Vbl"
      let ?state_d = "applyDecide ?state_up Vbl"
      
      have "InvariantConsistent (getM ?state_d)"
        using InvariantConsistentAfterApplyDecide [of "Vbl" "?state_up"]
        using False
        using ?inv' ?state_up
        by (simp add: Let_def)
      moreover
      have "InvariantUniq (getM ?state_d)"
        using InvariantUniqAfterApplyDecide [of "Vbl" "?state_up"]
        using False
        using ?inv' ?state_up
        by (simp add: Let_def)
      moreover
      have "InvariantQCharacterization (getConflictFlag ?state_d) (getQ ?state_d) (getF ?state_d) (getM ?state_d)"
        using InvariantQCharacterizationAfterApplyDecide [of "Vbl" "?state_up"]
        using False
        using ?inv' ?state_up
        using ¬ getConflictFlag ?state_up
        using ‹exhaustiveUnitPropagate_dom state
        using conflictFlagOrQEmptyAfterExhaustiveUnitPropagate[of "state"]
        by (simp add: Let_def)
      moreover
      have "InvariantConflictFlagCharacterization (getConflictFlag ?state_d) (getF ?state_d) (getM ?state_d)"
        using ‹InvariantConsistent (getM ?state_d)
        using ‹InvariantUniq (getM ?state_d)
        using InvariantConflictFlagCharacterizationAfterAssertLiteral[of "?state_up" "?literal" "True"]
        using ?inv' ?state_up
        using assertLiteralEffect
        unfolding applyDecide_def
        by (simp only: Let_def)
      moreover
      have "InvariantConflictClauseCharacterization (getConflictFlag ?state_d) (getConflictClause ?state_d) (getF ?state_d) (getM ?state_d)"
        using InvariantConflictClauseCharacterizationAfterAssertLiteral[of "?state_up" "?literal" "True"]
        using ?inv' ?state_up
        using assertLiteralEffect
        unfolding applyDecide_def
        by (simp only: Let_def)
      moreover
      have "InvariantNoDecisionsWhenConflict (getF ?state_d) (getM ?state_d) (currentLevel (getM ?state_d))"
        "InvariantNoDecisionsWhenUnit (getF ?state_d) (getM ?state_d) (currentLevel (getM ?state_d))"
        using ‹exhaustiveUnitPropagate_dom state
        using conflictFlagOrQEmptyAfterExhaustiveUnitPropagate[of "state"]
        using ¬ getConflictFlag ?state_up 
        using ?inv' ?state_up
        using ?inv'' ?state_up
        using InvariantsNoDecisionsWhenConflictNorUnitAfterAssertLiteral[of "?state_up" "True" "?literal"]
        unfolding applyDecide_def
        by (auto simp add: Let_def)
      moreover
      have "InvariantEquivalentZL (getF ?state_d) (getM ?state_d) F0'"
        using InvariantEquivalentZLAfterApplyDecide[of "?state_up" "F0'" "Vbl"]
        using ?inv' ?state_up
        using ‹InvariantEquivalentZL (getF ?state_up) (getM ?state_up) F0'
        by (simp add: Let_def)
      moreover
      have "InvariantGetReasonIsReason (getReason ?state_d) (getF ?state_d) (getM ?state_d) (set (getQ ?state_d))"
        using InvariantGetReasonIsReasonAfterApplyDecide[of "Vbl" "?state_up"]
        using ?inv' ?state_up
        using ‹InvariantGetReasonIsReason (getReason ?state_up) (getF ?state_up) (getM ?state_up) (set (getQ ?state_up))
        using False
        using ¬ getConflictFlag ?state_up 
        using ‹getConflictFlag ?state_up  getQ ?state_up = []
        by (simp add: Let_def)
      moreover
      have "getSATFlag ?state_d = getSATFlag state"
        unfolding applyDecide_def
        using ‹getSATFlag ?state_up = getSATFlag state
        using assertLiteralEffect[of "?state_up" "selectLiteral ?state_up Vbl" "True"]
        using ?inv' ?state_up
        by (simp only: Let_def)
      moreover
      have "InvariantVarsM (getM ?state_d) F0 Vbl"
        "InvariantVarsF (getF ?state_d) F0 Vbl"
        "InvariantVarsQ (getQ ?state_d) F0 Vbl"
        using InvariantsVarsAfterApplyDecide[of "Vbl" "?state_up"]
        using False
        using ?inv' ?state_up
        using ¬ getConflictFlag ?state_up
        using ‹getConflictFlag ?state_up  getQ ?state_up = []
        using ‹InvariantVarsM (getM ?state_up) F0 Vbl
        using ‹InvariantVarsQ (getQ ?state_up) F0 Vbl
        using ‹InvariantVarsF (getF ?state_up) F0 Vbl
        by (auto simp only: Let_def)
      moreover
      have "(?state_d, ?state_up)  terminationLessState1 (vars F0  Vbl)"
        using ‹getSATFlag ?state_up = getSATFlag state
        using assertLiteralEffect[of "?state_up" "selectLiteral ?state_up Vbl" "True"]
        using ?inv' ?state_up
        using ‹InvariantVarsM (getM state) F0 Vbl
        using ‹InvariantVarsM (getM ?state_up) F0 Vbl
        using ‹InvariantVarsM (getM ?state_d) F0 Vbl
        using ‹getSATFlag state = UNDEF›
        using ?inv' ?state_up
        using ‹InvariantConsistent (getM ?state_d)
        using ‹InvariantUniq (getM ?state_d)
        using lexLessAppend[of "[(selectLiteral ?state_up Vbl, True)]""getM ?state_up"]
        unfolding applyDecide_def
        unfolding terminationLessState1_def
        unfolding lexLessState1_def
        unfolding lexLessRestricted_def
        unfolding InvariantVarsM_def
        unfolding InvariantUniq_def
        unfolding InvariantConsistent_def
        by (simp add: Let_def)
      hence "(?state_d, state)  terminationLessState1 (vars F0  Vbl)"
        using ?state_up = state  (?state_up, state)  terminationLessState1 (vars F0  Vbl)
        using transTerminationLessState1I[of "?state_d" "?state_up" "vars F0  Vbl" "state"]
        by auto
      ultimately
      show ?thesis
        using ?inv' ?state_up
        using ‹getSATFlag state = UNDEF›
        using ¬ getConflictFlag ?state_up
        using False
        using WatchInvariantsAfterAssertLiteral[of "?state_up" "?literal" "True"]
        using InvariantWatchCharacterizationAfterAssertLiteral[of "?state_up" "?literal" "True"]
        using InvariantUniqQAfterAssertLiteral[of "?state_up" "?literal" "True"]
        using assertLiteralEffect[of "?state_up" "?literal" "True"]
        unfolding solve_loop_body_def
        unfolding applyDecide_def
        unfolding selectLiteral_def
        by (simp add: Let_def)
    qed
  qed
qed


(*****************************************************************************)
(*        S O L V E    L O O P                                               *)
(*****************************************************************************)

lemma SolveLoopTermination:
assumes
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)" and 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)" and
  "InvariantUniqQ (getQ state)" and
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)" and
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)" and
  "InvariantNoDecisionsWhenConflict (getF state) (getM state) (currentLevel (getM state))" and
  "InvariantNoDecisionsWhenUnit (getF state) (getM state) (currentLevel (getM state))" and
  "InvariantGetReasonIsReason (getReason state) (getF state) (getM state) (set (getQ state))" and
  "getSATFlag state = UNDEF  InvariantEquivalentZL (getF state) (getM state) F0'" and
  "InvariantConflictClauseCharacterization (getConflictFlag state) (getConflictClause state) (getF state) (getM state)" and
  "finite Vbl"
  "vars F0'  vars F0"
  "vars F0  Vbl"
  "InvariantVarsM (getM state) F0 Vbl"
  "InvariantVarsQ (getQ state) F0 Vbl"
  "InvariantVarsF (getF state) F0 Vbl"
shows
  "solve_loop_dom state Vbl"
using assms
proof (induct rule: wf_induct[of "terminationLessState1 (vars F0  Vbl)"])
  case 1
  thus ?case
    using ‹finite Vbl
    using finiteVarsFormula[of "F0"]
    using wellFoundedTerminationLessState1[of "vars F0  Vbl"]
    by simp
next
  case (2 state')
  note ih = this
  show ?case
  proof (cases "getSATFlag state' = UNDEF")
    case False
    show ?thesis
      apply (rule solve_loop_dom.intros)
      using False
      by simp
  next
    case True
    let ?state'' = "solve_loop_body state' Vbl"
    have
      "InvariantConsistent (getM ?state'')"
      "InvariantUniq (getM ?state'')"
      "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')" and 
      "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')" and 
      "InvariantWatchCharacterization (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') (getM ?state'')" and 
      "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state'') (getF ?state'')" and
      "InvariantWatchListsUniq (getWatchList ?state'')" and
      "InvariantWatchListsCharacterization (getWatchList ?state'') (getWatch1 ?state'') (getWatch2 ?state'')" and
      "InvariantUniqQ (getQ ?state'')" and
      "InvariantQCharacterization (getConflictFlag ?state'') (getQ ?state'') (getF ?state'') (getM ?state'')" and
      "InvariantConflictFlagCharacterization (getConflictFlag ?state'') (getF ?state'') (getM ?state'')" and
      "InvariantNoDecisionsWhenConflict (getF ?state'') (getM ?state'') (currentLevel (getM ?state''))" and
      "InvariantNoDecisionsWhenUnit (getF ?state'') (getM ?state'') (currentLevel (getM ?state''))" and
      "InvariantConflictClauseCharacterization (getConflictFlag ?state'') (getConflictClause ?state'') (getF ?state'') (getM ?state'')"
      "InvariantGetReasonIsReason (getReason ?state'') (getF ?state'') (getM ?state'') (set (getQ ?state''))"
      "InvariantEquivalentZL (getF ?state'') (getM ?state'') F0'"
      "InvariantVarsM (getM ?state'') F0 Vbl"
      "InvariantVarsQ (getQ ?state'') F0 Vbl"
      "InvariantVarsF (getF ?state'') F0 Vbl"
      "getSATFlag ?state'' = FALSE  ¬ satisfiable F0'"
      "getSATFlag ?state'' = TRUE   satisfiable F0'"
      "(?state'', state')  terminationLessState1 (vars F0  Vbl)"
     using InvariantsAfterSolveLoopBody[of "state'" "F0'" "Vbl" "F0"]
     using ih(2) ih(3) ih(4) ih(5) ih(6) ih(7) ih(8) ih(9) ih(10) ih(11) ih(12) ih(13) ih(14) ih(15)
           ih(16) ih(17) ih(18) ih(19) ih(20) ih(21) ih(22) ih(23)
     using True
     by (auto simp only: Let_def)
   hence "solve_loop_dom ?state'' Vbl"
     using ih
     by auto
   thus ?thesis
     using solve_loop_dom.intros[of "state'" "Vbl"]
     using True
     by simp
 qed
qed


lemma SATFlagAfterSolveLoop:
assumes
  "solve_loop_dom state Vbl"
  "InvariantConsistent (getM state)"
  "InvariantUniq (getM state)"
  "InvariantWatchesEl (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchesDiffer (getF state) (getWatch1 state) (getWatch2 state)" and 
  "InvariantWatchCharacterization (getF state) (getWatch1 state) (getWatch2 state) (getM state)" and 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList state) (getF state)" and
  "InvariantWatchListsUniq (getWatchList state)" and
  "InvariantWatchListsCharacterization (getWatchList state) (getWatch1 state) (getWatch2 state)" and
  "InvariantUniqQ (getQ state)" and
  "InvariantQCharacterization (getConflictFlag state) (getQ state) (getF state) (getM state)" and
  "InvariantConflictFlagCharacterization (getConflictFlag state) (getF state) (getM state)" and
  "InvariantNoDecisionsWhenConflict (getF state) (getM state) (currentLevel (getM state))" and
  "InvariantNoDecisionsWhenUnit (getF state) (getM state) (currentLevel (getM state))" and
  "InvariantGetReasonIsReason (getReason state) (getF state) (getM state) (set (getQ state))" and
  "getSATFlag state = UNDEF  InvariantEquivalentZL (getF state) (getM state) F0'" and
  "InvariantConflictClauseCharacterization (getConflictFlag state) (getConflictClause state) (getF state) (getM state)"
  "getSATFlag state = FALSE  ¬ satisfiable F0'"
  "getSATFlag state = TRUE   satisfiable F0'"
  "finite Vbl"
  "vars F0'  vars F0"
  "vars F0  Vbl"
  "InvariantVarsM (getM state) F0 Vbl"
  "InvariantVarsF (getF state) F0 Vbl"
  "InvariantVarsQ (getQ state) F0 Vbl"
shows
  "let state' = solve_loop state Vbl in 
         (getSATFlag state' = FALSE  ¬ satisfiable F0')  (getSATFlag state' = TRUE   satisfiable F0')"
using assms
proof (induct state Vbl rule: solve_loop_dom.induct)
  case (step state' Vbl)
  note ih = this
  show ?case
  proof (cases "getSATFlag state' = UNDEF")
    case False
    with solve_loop.simps[of "state'"]
    have "solve_loop state' Vbl = state'"
      by simp
    thus ?thesis
      using False
      using ih(19) ih(20)
      using ExtendedBool.nchotomy
      by (auto simp add: Let_def)
  next
    case True
    let ?state'' = "solve_loop_body state' Vbl"
    have "solve_loop state' Vbl = solve_loop ?state'' Vbl"
      using solve_loop.simps[of "state'"]
      using True
      by (simp add: Let_def)
    moreover
    have "InvariantEquivalentZL (getF state') (getM state') F0'"
      using True
      using ih(17)
      by simp
    hence
      "InvariantConsistent (getM ?state'')"
      "InvariantUniq (getM ?state'')"
      "InvariantWatchesEl (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')" and 
      "InvariantWatchesDiffer (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'')" and 
      "InvariantWatchCharacterization (getF ?state'') (getWatch1 ?state'') (getWatch2 ?state'') (getM ?state'')" and 
      "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?state'') (getF ?state'')" and
      "InvariantWatchListsUniq (getWatchList ?state'')" and
      "InvariantWatchListsCharacterization (getWatchList ?state'') (getWatch1 ?state'') (getWatch2 ?state'')" and
      "InvariantUniqQ (getQ ?state'')" and
      "InvariantQCharacterization (getConflictFlag ?state'') (getQ ?state'') (getF ?state'') (getM ?state'')" and
      "InvariantConflictFlagCharacterization (getConflictFlag ?state'') (getF ?state'') (getM ?state'')" and
      "InvariantNoDecisionsWhenConflict (getF ?state'') (getM ?state'') (currentLevel (getM ?state''))" and
      "InvariantNoDecisionsWhenUnit (getF ?state'') (getM ?state'') (currentLevel (getM ?state''))" and
      "InvariantConflictClauseCharacterization (getConflictFlag ?state'') (getConflictClause ?state'') (getF ?state'') (getM ?state'')"
      "InvariantGetReasonIsReason (getReason ?state'') (getF ?state'') (getM ?state'') (set (getQ ?state''))"
      "InvariantEquivalentZL (getF ?state'') (getM ?state'') F0'"
      "InvariantVarsM (getM ?state'') F0 Vbl"
      "InvariantVarsQ (getQ ?state'') F0 Vbl"
      "InvariantVarsF (getF ?state'') F0 Vbl"
      "getSATFlag ?state'' = FALSE  ¬ satisfiable F0'"
      "getSATFlag ?state'' = TRUE   satisfiable F0'"
      using ih(1) ih(3) ih(4) ih(5) ih(6) ih(7) ih(8) ih(9) ih(10) ih(11) ih(12) ih(13) ih(14)
            ih(15) ih(16) ih(18) ih(21) ih(22) ih(23) ih(24) ih(25) ih(26)
      using InvariantsAfterSolveLoopBody[of "state'" "F0'" "Vbl" "F0"]
      using True
      by (auto simp only: Let_def)
    ultimately
    show ?thesis
      using True
      using ih(2)
      using ih(21)
      using ih(22)
      using ih(23)
      by (simp add: Let_def)
  qed
qed

      

end

Theory FunctionalImplementation

theory FunctionalImplementation
imports Initialization SolveLoop
begin

(******************************************************************************)
subsection‹Total correctness theorem›
(******************************************************************************)

theorem correctness:
shows 
"(solve F0 = TRUE  satisfiable F0)  (solve F0 = FALSE  ¬ satisfiable F0)"
proof-
  let ?istate = "initialize F0 initialState"
  let ?F0' = "filter (λ c. ¬ clauseTautology c) F0"
  have
  "InvariantConsistent (getM ?istate)"
  "InvariantUniq (getM ?istate)"
  "InvariantWatchesEl (getF ?istate) (getWatch1 ?istate) (getWatch2 ?istate)" and 
  "InvariantWatchesDiffer (getF ?istate) (getWatch1 ?istate) (getWatch2 ?istate)" and 
  "InvariantWatchCharacterization (getF ?istate) (getWatch1 ?istate) (getWatch2 ?istate) (getM ?istate)" and 
  "InvariantWatchListsContainOnlyClausesFromF (getWatchList ?istate) (getF ?istate)" and
  "InvariantWatchListsUniq (getWatchList ?istate)" and
  "InvariantWatchListsCharacterization (getWatchList ?istate) (getWatch1 ?istate) (getWatch2 ?istate)" and
  "InvariantUniqQ (getQ ?istate)" and
  "InvariantQCharacterization (getConflictFlag ?istate) (getQ ?istate) (getF ?istate) (getM ?istate)" and
  "InvariantConflictFlagCharacterization (getConflictFlag ?istate) (getF ?istate) (getM ?istate)" and
  "InvariantNoDecisionsWhenConflict (getF ?istate) (getM ?istate) (currentLevel (getM ?istate))" and
  "InvariantNoDecisionsWhenUnit (getF ?istate) (getM ?istate) (currentLevel (getM ?istate))" and
  "InvariantGetReasonIsReason (getReason ?istate) (getF ?istate) (getM ?istate) (set (getQ ?istate))" and
  "InvariantConflictClauseCharacterization (getConflictFlag ?istate) (getConflictClause ?istate) (getF ?istate) (getM ?istate)"
  "InvariantVarsM (getM ?istate) F0 (vars F0)"
  "InvariantVarsQ (getQ ?istate) F0 (vars F0)"
  "InvariantVarsF (getF ?istate) F0 (vars F0)"
  "getSATFlag ?istate = UNDEF  InvariantEquivalentZL (getF ?istate) (getM ?istate) ?F0'" and
  "getSATFlag ?istate = FALSE  ¬ satisfiable ?F0'"
  "getSATFlag ?istate = TRUE   satisfiable F0"
    using InvariantsAfterInitialization[of "F0"]
    using InvariantEquivalentZLAfterInitialization[of "F0"]
    unfolding InvariantVarsM_def
    unfolding InvariantVarsF_def
    unfolding InvariantVarsQ_def
    by (auto simp add: Let_def)
  moreover
  hence "solve_loop_dom ?istate (vars F0)"
    using SolveLoopTermination[of "?istate" "?F0'" "vars F0" "F0"]
    using finiteVarsFormula[of "F0"]
    using varsSubsetFormula[of "?F0'" "F0"]
    by auto
  ultimately
  show ?thesis
    using finiteVarsFormula[of "F0"]
    using SATFlagAfterSolveLoop[of "?istate" "vars F0" "?F0'" "F0"]
    using satisfiableFilterTautologies[of "F0"]
    unfolding solve_def
    using varsSubsetFormula[of "?F0'" "F0"]
    by (auto simp add: Let_def)
qed

end